Skip to content

Commit

Permalink
fix instance null when involve async destruction
Browse files Browse the repository at this point in the history
  • Loading branch information
yiminghe committed Feb 23, 2016
1 parent de09e0a commit ae5e2d8
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 3 deletions.
7 changes: 4 additions & 3 deletions src/renderers/shared/reconciler/ReactOwner.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,10 @@ var ReactOwner = {
'`render` method, or you have multiple copies of React loaded ' +
'(details: https://fb.me/react-refs-must-have-owner).'
);
// Check that `component` is still the current ref because we do not want to
// detach the ref if another component stole it.
if (owner.getPublicInstance().refs[ref] === component.getPublicInstance()) {
var ownerPublicInstance = owner.getPublicInstance();
// Check that `component`'s owner is still alive and that `component` is still the current ref
// because we do not want to detach the ref if another component stole it.
if (ownerPublicInstance && ownerPublicInstance.refs[ref] === component.getPublicInstance()) {
owner.detachRef(ref);
}
},
Expand Down
48 changes: 48 additions & 0 deletions src/renderers/shared/reconciler/__tests__/refs-destruction-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,52 @@ describe('refs-destruction', function() {
ReactDOM.render(<TestComponent destroy={true} />, container);
expect(Object.keys(testInstance.refs || {}).length).toEqual(0);
});

it('should not error when destroying child with ref asynchronously', function() {
var flag = false;
runs(function() {
var Modal = React.createClass({
componentDidMount: function() {
this.div = document.createElement('div');
document.body.appendChild(this.div);
this.componentDidUpdate();
},
componentDidUpdate: function() {
ReactDOM.render(<div>{this.props.children}</div>, this.div);
},
componentWillUnmount: function() {
var self = this;
// some async animation
setImmediate(function() {
expect(function() {
ReactDOM.unmountComponentAtNode(self.div);
}).not.toThrow();
document.body.removeChild(self.div);
flag = true;
});
},
render() {
return null;
},
});
var AppModal = React.createClass({
render: function() {
return (<Modal>
<a ref="ref"/>
</Modal>);
},
});
var App = React.createClass({
render: function() {
return this.props.hidden ? null : <AppModal onClose={this.close}/>;
},
});
var container = document.createElement('div');
ReactDOM.render(<App />, container);
ReactDOM.render(<App hidden={true}/>, container);
});
waitsFor(function() {
return flag;
}, 'unmount should be ok', 10);
});
});

0 comments on commit ae5e2d8

Please sign in to comment.