-
Notifications
You must be signed in to change notification settings - Fork 46.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Batching can update one component twice, causing unpredictable lifecycle #2410
Comments
I've spent all day on this and still no closer to solving it. I have since found out though that if I use the ESC key to close the modal no error is thrown... |
Like the error says, it seems your calling |
This is the point tho, the |
I'm debugging deep into the core now and ALL |
I have temporarily "fixed" this by calling |
@m4tthumphrey Can you build a simple repro case for this on jsbin or jsfiddle? This does sound like a bug but without a way for me to reproduce it it'll be hard to fix. |
I'll try to reproduce this on jsf tomorrow... @spicyj |
Still haven't had a chance to replicate but it appears that this is only happening Firefox and IE and not in Chrome. |
@spicyj I don't think I'm going to be able to replicate this outside of my app (its too big). If I make the app available to you publically, would that help? |
K, so I've wrapped
and all is good in all browsers. Obviously there is a bug somewhere but I'm too deep in this problem to find the root cause. I will leave this issue open and if anyone fancies digging into it let me know and I'll set up a public version of the dev app so you can take a look. |
I think this should be fixed in master thanks to #2503 |
Hey guys, I actually updated to 12.1 today and I tested it before adding the hack and it has been working fine so looks like it was fixed in 0.12.1 somewhere :) |
0.12.1 just had changes to JSX so if you were on 0.12 before you shouldn't see any difference. |
@m4tthumphrey Do you have a repro case for this? Are you sure you're calling getDOMNode at a time that the node is still in the DOM? |
Well yes I guess so. It works fine in 0.12.2. And no its so baked in my app that I can't repro it without uploading the test app, which I'm happy to do if it helps. The call to var button = this.refs.tooltip.getDOMNode(); |
This is getting me too after upgrading to 0.13. The problem seems to exist with an input that I have nested in a few components within a React Bootstrap Modal and I close the modal. I can't get much more of a trace on this than that though... |
@mfunkie Yes that case sounds exactly the same except I'm not using bootstrap. |
More on this, with my modal, I'm using the React Bootstrap Overlay Mixin which creates a new React tree. If I just render the Modal as a child component, opening and closing it does not trigger the error anymore. Could this be related to React elements being on a different Tree, |
It turns out in my issue, I had two components listening to the same Flux Store. The Container component that would run the Overlay, and the inner body of the Modal. By adding the following function to the inner Modal Body, I was able to avoid the error
My best guess is that the change listener was still queued up to run and an inner state was rendered after the Modal had already been considered closed. |
@mfunkie I'm having the same issue as you, I was using react-modal before and just changed to the one in react-bootstrap. |
I'm also using react-bootstrap and ran into this issue. I'm using react@0.12.2, react-bootstrap@0.17.0 @mfunkie workaround fixed it for me. Thanks! |
This tripped me, I'd have expected |
I guess throwing makes sense, but the error message is too cryptic:
I honestly thought I had duplicate React or something, so I didn't even bother to check whether the component was mounted. (It wasn't.) |
The error does not happen if this line is removed: https://github.com/aaronjensen/react-2410-repro/blob/master/app/create_router.jsx#L10 |
@spicyj I know, I wasn't criticising or anything, just updating the issue. To be honest I haven't looked into this issue for months as still use the temp solution mentioned above. I'll revisit this week. |
@aaronjensen Thanks for the repro case. I'll try to look into this. @m4tthumphrey No worries. |
Okay, I tracked down the root cause. If updates to a parent and child component are both enqueued during a batch and while the parent is updating another update to the child is enqueued, we end up reconciling the child twice which breaks other assumptions and interleaves lifecycle methods incorrectly. In both 0.13.2 and master (if you fix the batchedUpdates reference), this code var Parent = React.createClass({
getChild: function() {
return this.refs.child;
},
render: function() {
return <Child ref="child" />;
}
});
var once = false;
var Child = React.createClass({
getInitialState: function() {
return {updated: false};
},
componentWillUpdate: function() {
if (!once) {
once = true;
this.setState({updated: true});
}
},
componentDidUpdate: function() {
console.log('child update');
},
render: function() {
console.log('child render');
return <div />;
}
});
var parent = React.render(<Parent />, document.getElementById('container'));
var child = parent.getChild();
console.log('--- start of batch');
React.addons.batchedUpdates(function() {
parent.forceUpdate();
child.forceUpdate();
});
console.log('-- end of batch'); produces the output
where the render and update lines should be interleaved. |
I thought we had a warning for setState in componentWillUpdate but I guess not. |
Just an quick update. I thought I'd give 0.13.3 a go and straight away ran into
Which doesn't happen on 0.12.2 (the version I'm currently resting on). |
@m4tthumphrey That message means the same as "Invariant Violation: getDOMNode(): A component must be mounted to have a DOM node." In #4727 I improved the message to make it a bit clearer. I wouldn't expect this issue to be fixed until we make a specific attempt to fix it at which time you'll see stuff happening on this issue. |
I've just upgraded my app to 0.14 and so far I haven't been able to reproduce this bug. @spicyj could anything you know of fixed this prior to the 0.14 release? |
No, it isn't fixed. The test case I posted still has the problem. |
#3762 has a nice repro from @scarletsky; should verify that it gets fixed too. |
Fixes facebook#2410. Fixes facebook#6371. Fixes facebook#6538. I also manually tested the codepen in facebook#3762 and verified it now works.
Fixes facebook#2410. Fixes facebook#6371. Fixes facebook#6538. I also manually tested the codepen in facebook#3762 and verified it now works.
This one is hard to explain or reproduce but I'll try...
I'm using the following mixin which has changed slightly from the original I found in a gist a while back:
This allows me to create layered components, in my case a modal dialog. I use the following component to build my modals:
This combination works perfectly. That is until I close the highest modal. If an
<input />
component is used inside of the<Modal>
render method, iethis.props.children
, the following error is thrown. All other element types (that I've tried includingtextarea
andselect
work fine, butinput
throws the following:Uncaught Error: Invariant Violation: getDOMNode(): A component must be mounted to have a DOM node
The trace is as follows:
ReactCompositeComponent.createClass.componentDidUpdate bundle.js:64334
is here.This only happens when there are several modals on top of each other; one dialog with an
<input />
runs fine with no error.The weird thing is that the app still runs fine, the error thrown has no impact (apart from being thrown) on how my app performs....
This is on 0.12RC1 using webpack to build.
The text was updated successfully, but these errors were encountered: