Skip to content

Commit

Permalink
Merge pull request #6095 from yiminghe/fix-async-ref-destruct
Browse files Browse the repository at this point in the history
fix instance null when involve async destruction
  • Loading branch information
jimfb committed Mar 9, 2016
2 parents 11b5523 + df095c0 commit 2f4a8e9
Show file tree
Hide file tree
Showing 2 changed files with 46 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
42 changes: 42 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,46 @@ 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 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
setTimeout(function() {
expect(function() {
ReactDOM.unmountComponentAtNode(self.div);
}).not.toThrow();
document.body.removeChild(self.div);
}, 0);
},
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);
jest.runAllTimers();
});
});

0 comments on commit 2f4a8e9

Please sign in to comment.