From 2afd7186ae5a8978e9f5fec56031bddca6545c2d Mon Sep 17 00:00:00 2001 From: Ben Alpert Date: Sun, 9 Jun 2013 17:21:22 -0700 Subject: [PATCH] Run inner componentDidMount method first Fixes #76. --- src/core/ReactCompositeComponent.js | 12 ++-- .../__tests__/ReactComponentLifeCycle-test.js | 66 +++++++++++++++++++ 2 files changed, 73 insertions(+), 5 deletions(-) diff --git a/src/core/ReactCompositeComponent.js b/src/core/ReactCompositeComponent.js index 468c200511..cfbe109833 100644 --- a/src/core/ReactCompositeComponent.js +++ b/src/core/ReactCompositeComponent.js @@ -451,17 +451,19 @@ var ReactCompositeComponentMixin = { } } - if (this.componentDidMount) { - transaction.getReactOnDOMReady().enqueue(this, this.componentDidMount); - } - this._renderedComponent = this._renderValidatedComponent(); // Done with mounting, `setState` will now trigger UI changes. this._compositeLifeCycleState = null; this._lifeCycleState = ReactComponent.LifeCycle.MOUNTED; - return this._renderedComponent.mountComponent(rootID, transaction); + var html = this._renderedComponent.mountComponent(rootID, transaction); + + if (this.componentDidMount) { + transaction.getReactOnDOMReady().enqueue(this, this.componentDidMount); + } + + return html; }, /** diff --git a/src/core/__tests__/ReactComponentLifeCycle-test.js b/src/core/__tests__/ReactComponentLifeCycle-test.js index 4c1f92e465..9d809aaa5d 100644 --- a/src/core/__tests__/ReactComponentLifeCycle-test.js +++ b/src/core/__tests__/ReactComponentLifeCycle-test.js @@ -429,5 +429,71 @@ describe('ReactComponentLifeCycle', function() { expect(instance.state.stateField).toBe('goodbye'); }); + it('should call nested lifecycle methods in the right order', function() { + var log; + var logger = function(msg) { + return function() { + // return true for shouldComponentUpdate + log.push(msg); + return true; + }; + }; + var Outer = React.createClass({ + render: function() { + return
; + }, + componentWillMount: logger('outer componentWillMount'), + componentDidMount: logger('outer componentDidMount'), + componentWillReceiveProps: logger('outer componentWillReceiveProps'), + shouldComponentUpdate: logger('outer shouldComponentUpdate'), + componentWillUpdate: logger('outer componentWillUpdate'), + componentDidUpdate: logger('outer componentDidUpdate'), + componentWillUnmount: logger('outer componentWillUnmount') + }); + var Inner = React.createClass({ + render: function() { + return {this.props.x}; + }, + componentWillMount: logger('inner componentWillMount'), + componentDidMount: logger('inner componentDidMount'), + componentWillReceiveProps: logger('inner componentWillReceiveProps'), + shouldComponentUpdate: logger('inner shouldComponentUpdate'), + componentWillUpdate: logger('inner componentWillUpdate'), + componentDidUpdate: logger('inner componentDidUpdate'), + componentWillUnmount: logger('inner componentWillUnmount') + }); + var instance; + var node; + + log = []; + instance = ReactTestUtils.renderIntoDocument(); + expect(log).toEqual([ + 'outer componentWillMount', + 'inner componentWillMount', + 'inner componentDidMount', + 'outer componentDidMount' + ]); + + log = []; + instance.setProps({x: 42}); + expect(log).toEqual([ + 'outer componentWillReceiveProps', + 'outer shouldComponentUpdate', + 'outer componentWillUpdate', + 'inner componentWillReceiveProps', + 'inner shouldComponentUpdate', + 'inner componentWillUpdate', + 'inner componentDidUpdate', + 'outer componentDidUpdate' + ]); + + log = []; + instance.unmountComponent(); + expect(log).toEqual([ + 'outer componentWillUnmount', + 'inner componentWillUnmount' + ]); + }); + });