diff --git a/src/addons/transitions/ReactCSSTransitionGroupChild.js b/src/addons/transitions/ReactCSSTransitionGroupChild.js index 304232689c..c5332044f5 100644 --- a/src/addons/transitions/ReactCSSTransitionGroupChild.js +++ b/src/addons/transitions/ReactCSSTransitionGroupChild.js @@ -100,6 +100,7 @@ var ReactCSSTransitionGroupChild = React.createClass({ if (userSpecifiedDelay) { // Clean-up the animation after the specified delay timeout = setTimeout(endListener, userSpecifiedDelay); + this.transitionTimeouts.push(timeout); } else { // DEPRECATED: this listener will be removed in a future version of react ReactTransitionEvents.addEndEventListener(node, endListener); @@ -126,12 +127,16 @@ var ReactCSSTransitionGroupChild = React.createClass({ componentWillMount: function() { this.classNameQueue = []; + this.transitionTimeouts = []; }, componentWillUnmount: function() { if (this.timeout) { clearTimeout(this.timeout); } + this.transitionTimeouts.forEach(function(timeout) { + clearTimeout(timeout); + }); }, componentWillAppear: function(done) { diff --git a/src/addons/transitions/__tests__/ReactCSSTransitionGroup-test.js b/src/addons/transitions/__tests__/ReactCSSTransitionGroup-test.js index b56eb237a2..ce1d14a4b9 100644 --- a/src/addons/transitions/__tests__/ReactCSSTransitionGroup-test.js +++ b/src/addons/transitions/__tests__/ReactCSSTransitionGroup-test.js @@ -269,4 +269,26 @@ describe('ReactCSSTransitionGroup', function() { var leavingNode = ReactDOM.findDOMNode(a).childNodes[0]; expect(CSSCore.hasClass(leavingNode, 'custom-leaving')).toBe(true); }); + + it('should clear transition timeouts when unmounted', function() { + var Component = React.createClass({ + render: function() { + return ( + + {this.props.children} + + ); + }, + }); + + ReactDOM.render(, container); + ReactDOM.render(, container); + + ReactDOM.unmountComponentAtNode(container); + + // Testing that no exception is thrown here, as the timeout has been cleared. + jest.runAllTimers(); + }); });