Change:
When unmounting components like this: a memory leak happens because ReactMount.getID(node) puts DOM nodes back to nodeCache if they are not there.. just right after they were purged from cache. Here is what's happing when unmounting that example component: label component gets purged from nodeCache when ReactDOMInput component is going to unmount it calls this method: which contains this.getDOMNode() which iterates through the children of the Form element calling getID() on each of them.. which puts these elements back into the cache. So first they were purged and here they are all put back in cache causing a memory leak :( I'm playing with React just 3rd day so not sure of a way to correctly fix this issue
(I took the liberty to edit your comment to add syntax highlighting)
I can't reproduce this. With this diff applied, I loaded http://127.0.0.1:8000/examples/ballmer-peak/ in the console and checked -- it was empty. Am I misunderstanding?
Yes. You've missed one more user defined component in there.. Here you go:
Thanks, fixed in .
Thank you for fast fix :)
Thanks for the find/fix!

Discussion:
this._defaultProps = null; <del> ReactComponent.Mixin.unmountComponent.call(this); </del> this._renderedComponent.unmountComponent(); this._renderedComponent = null; <ins> ReactComponent.Mixin.unmountComponent.call(this); </ins> if (this.refs) { this.refs = null; }

* @internal */ unmountComponent: function() { <ins> this.unmountChildren(); </ins> ReactEventEmitter.deleteAllListeners(this._rootNodeID); ReactComponent.Mixin.unmountComponent.call(this); <del> this.unmountChildren(); </del> } };

var MorphingComponent; var ChildUpdates; var React; <ins> var ReactComponent; </ins> var ReactCurrentOwner; var ReactPropTypes; var ReactTestUtils;

reactComponentExpect = require('reactComponentExpect'); React = require('React'); <ins> ReactComponent = require('ReactComponent'); </ins> ReactCurrentOwner = require('ReactCurrentOwner'); ReactDoNotBindDeprecated = require('ReactDoNotBindDeprecated'); ReactPropTypes = require('ReactPropTypes');

}); }); <ins> it('should call componentWillUnmount before unmounting', function() { var container = document.createElement('div'); var innerUnmounted = false; spyOn(ReactMount, 'purgeID').andCallThrough(); var Component = React.createClass({ render: function() { return <div> <Inner /> </div>; } }); var Inner = React.createClass({ componentWillUnmount: function() { // It's important that ReactMount.purgeID be called after any component // lifecycle methods, because a componentWillMount implementation is // likely call this.getDOMNode(), which will repopulate the node cache // after it's been cleared, causing a memory leak. expect(ReactMount.purgeID.callCount).toBe(0); innerUnmounted = true; }, render: function() { return <div />; } }); React.renderComponent(<Component />, container); React.unmountComponentAtNode(container); expect(innerUnmounted).toBe(true); // <Component />, <Inner />, and both <div /> elements each call // unmountIDFromEnvironment which calls purgeID, for a total of 4. expect(ReactMount.purgeID.callCount).toBe(4); }); </ins> it('should detect valid CompositeComponent classes', function() { var Component = React.createClass({ render: function() {