Change:
tl;dr: If you have a component that returns and it rerenders, the noscript tag is unmounted and a new one is created because shouldUpdateReactComponent gets and and returns false. This came out of some internal components that were breaking after the most recent update. I haven't gone to see if this is more widely broken - it might have been before any of the recent updates, just that the empty component is triggering it reliably. I've been some reports of having similar weird problems that we couldn't track down. It's use of is very similar to what's happening in . The trigger here is that we're triggering an update during the mount phase. When we do this works correctly because it's before which is triggering to rerender. is the broken one because its hasn't been called yet. So we actually call its first. Then we still call its . There's also the whole question of why we're trying to unmount anything at all here. It seems like we shouldn't be doing that. cc Drop this into examples/basic-jsx-harmony and debug with pausing on caught exceptions. I some breakpoints in ReactEmptyComponent to make it super obvious.
Why it's unmounting: When comparing the old to the new in , is actually whereas is , so returns false.
Why it's throwing: the three componentDidMount calls get queued in the order they were rendered (Child 0's null, Child 1, Child 2's null), but because batching doesn't happen on an initial render (something I've been meaning to make happen…), the forceUpdate happens synchronously and causes the unmount/remount of both child components, after which the old enqueued Child 2 null did-mount callback runs and throws, because that component isn't mounted any more.
(Two issues; we should fix both.)
The first one is a new regression, right?
Not sure, but I think so. I a test recently to ensure that text components don't get remounted on update; we should add one for empty components too.
Initial render isn't asynchronous but to change it, I think we'd need to change the API to pass the instance to a callback instead of synchronously returning it. We should be able to queue up new updates during initial render though. So that they're guaranteed to happen after the queue as processed.
Right -- that's what we do already for new mounts of child components within a larger update.
The second issue should be fixed now because we batch on initial render. Not sure about the first; it's probably still a problem.
I just ran into this (I think) and made a JSFiddle for it
Maybe you can fix this.
Suggestion to use instead of so that it doesn't mess up s and s.

Discussion:
var ReactEmptyComponentType = function() {}; ReactEmptyComponentType.prototype.componentDidMount = function() { var internalInstance = ReactInstanceMap.get(this); <ins> // TODO: Make sure we run these methods in the correct order, we shouldn't // need this check. We're going to assume if we're here it means we ran // componentWillUnmount already so there is no internal instance (it gets // removed as part of the unmounting process). if (!internalInstance) { return; } </ins> registerNullComponentID(internalInstance._rootNodeID); }; ReactEmptyComponentType.prototype.componentWillUnmount = function() { var internalInstance = ReactInstanceMap.get(this); <ins> // TODO: Get rid of this check. See TODO in componentDidMount. if (!internalInstance) { return; } </ins> deregisterNullComponentID(internalInstance._rootNodeID); }; ReactEmptyComponentType.prototype.render = function() {

'Invariant Violation: React.render(): Invalid component element.' ); }); <ins> it('does not break when updating during mount', function() { var Child = React.createClass({ componentDidMount() { this.props.onMount && this.props.onMount(); }, render() { if (!this.props.visible) { return null; } return <div>hello world</div>; } }); var Parent = React.createClass({ update() { this.forceUpdate(); }, render() { return ( <div> <Child key="1" visible={false} /> <Child key="0" visible={true} onMount={this.update} /> <Child key="2" visible={false} /> </div> ); } }); expect(function() { ReactTestUtils.renderIntoDocument(<Parent/>) }).not.toThrow(); }); </ins> });