diff --git a/src/addons/ReactRAFBatchingStrategy.js b/src/addons/ReactRAFBatchingStrategy.js index 1d3df579a7a28..198faf259e408 100644 --- a/src/addons/ReactRAFBatchingStrategy.js +++ b/src/addons/ReactRAFBatchingStrategy.js @@ -31,8 +31,8 @@ var ReactRAFBatchingStrategy = { * Call the provided function in a context within which calls to `setState` * and friends are batched such that components aren't updated unnecessarily. */ - batchedUpdates: function(callback, a, b) { - callback(a, b); + batchedUpdates: function(callback, a, b, c, d) { + callback(a, b, c, d); } }; diff --git a/src/browser/ui/ReactMount.js b/src/browser/ui/ReactMount.js index 5b030c447e44d..7950ff1019edd 100644 --- a/src/browser/ui/ReactMount.js +++ b/src/browser/ui/ReactMount.js @@ -233,23 +233,51 @@ function findDeepestCachedAncestor(targetID) { /** * Mounts this component and inserts it into the DOM. * + * @param {ReactComponent} componentInstance The instance to mount. * @param {string} rootID DOM ID of the root node. * @param {DOMElement} container DOM element to mount into. * @param {ReactReconcileTransaction} transaction * @param {boolean} shouldReuseMarkup If true, do not insert markup */ function mountComponentIntoNode( + componentInstance, rootID, container, transaction, shouldReuseMarkup) { var markup = ReactReconciler.mountComponent( - this, rootID, transaction, emptyObject + componentInstance, rootID, transaction, emptyObject ); - this._isTopLevel = true; + componentInstance._isTopLevel = true; ReactMount._mountImageIntoNode(markup, container, shouldReuseMarkup); } +/** + * Batched mount. + * + * @param {ReactComponent} componentInstance The instance to mount. + * @param {string} rootID DOM ID of the root node. + * @param {DOMElement} container DOM element to mount into. + * @param {boolean} shouldReuseMarkup If true, do not insert markup + */ +function batchedMountComponentIntoNode( + componentInstance, + rootID, + container, + shouldReuseMarkup) { + var transaction = ReactUpdates.ReactReconcileTransaction.getPooled(); + transaction.perform( + mountComponentIntoNode, + null, + componentInstance, + rootID, + container, + transaction, + shouldReuseMarkup + ); + ReactUpdates.ReactReconcileTransaction.release(transaction); +} + /** * Mounting is the process of initializing a React component by creatings its * representative DOM elements and inserting them into a supplied `container`. @@ -368,16 +396,17 @@ var ReactMount = { container ); - var transaction = ReactUpdates.ReactReconcileTransaction.getPooled(); - transaction.perform( - mountComponentIntoNode, + // The initial render is synchronous but any updates that happen during + // rendering, in componentWillMount or componentDidMount, will be batched + // according to the current batching strategy. + + ReactUpdates.batchedUpdates( + batchedMountComponentIntoNode, componentInstance, reactRootID, container, - transaction, shouldReuseMarkup ); - ReactUpdates.ReactReconcileTransaction.release(transaction); if (__DEV__) { // Record the root element in case it later gets transplanted. diff --git a/src/core/ReactDefaultBatchingStrategy.js b/src/core/ReactDefaultBatchingStrategy.js index 37e64a36d8013..d996adad1dc6f 100644 --- a/src/core/ReactDefaultBatchingStrategy.js +++ b/src/core/ReactDefaultBatchingStrategy.js @@ -54,16 +54,16 @@ var ReactDefaultBatchingStrategy = { * Call the provided function in a context within which calls to `setState` * and friends are batched such that components aren't updated unnecessarily. */ - batchedUpdates: function(callback, a, b) { + batchedUpdates: function(callback, a, b, c, d) { var alreadyBatchingUpdates = ReactDefaultBatchingStrategy.isBatchingUpdates; ReactDefaultBatchingStrategy.isBatchingUpdates = true; // The code is written this way to avoid extra allocations if (alreadyBatchingUpdates) { - callback(a, b); + callback(a, b, c, d); } else { - transaction.perform(callback, null, a, b); + transaction.perform(callback, null, a, b, c, d); } } }; diff --git a/src/core/ReactUpdates.js b/src/core/ReactUpdates.js index dc84254f06e5a..3311874a2635e 100644 --- a/src/core/ReactUpdates.js +++ b/src/core/ReactUpdates.js @@ -104,9 +104,9 @@ assign( PooledClass.addPoolingTo(ReactUpdatesFlushTransaction); -function batchedUpdates(callback, a, b) { +function batchedUpdates(callback, a, b, c, d) { ensureInjected(); - batchingStrategy.batchedUpdates(callback, a, b); + batchingStrategy.batchedUpdates(callback, a, b, c, d); } /** diff --git a/src/core/__tests__/ReactCompositeComponentState-test.js b/src/core/__tests__/ReactCompositeComponentState-test.js index ffa1ac2e8ac49..50e90efb868e4 100644 --- a/src/core/__tests__/ReactCompositeComponentState-test.js +++ b/src/core/__tests__/ReactCompositeComponentState-test.js @@ -155,9 +155,9 @@ describe('ReactCompositeComponent-state', function() { [ 'componentDidMount-start', 'orange', null ], // setState-sunrise and setState-orange should be called here, // after the bug in #1740 - // componentDidMount() called setState({color:'yellow'}), currently this - // occurs inline. - // In a future where setState() is async, this test result will change. + // componentDidMount() called setState({color:'yellow'}), which is async. + // The update doesn't happen until the next flush. + [ 'componentDidMount-end', 'orange', 'yellow' ], [ 'shouldComponentUpdate-currentState', 'orange', null ], [ 'shouldComponentUpdate-nextState', 'yellow' ], [ 'componentWillUpdate-currentState', 'orange', null ], @@ -166,8 +166,6 @@ describe('ReactCompositeComponent-state', function() { [ 'componentDidUpdate-currentState', 'yellow', null ], [ 'componentDidUpdate-prevState', 'orange' ], [ 'setState-yellow', 'yellow', null ], - // componentDidMount() finally closes. - [ 'componentDidMount-end', 'yellow', null ], [ 'initial-callback', 'yellow', null ], [ 'componentWillReceiveProps-start', 'yellow', null ], // setState({color:'green'}) only enqueues a pending state.