diff --git a/docs/docs/api.md b/docs/docs/api.md index fd29070ecbc..1ae5e97b37f 100644 --- a/docs/docs/api.md +++ b/docs/docs/api.md @@ -108,15 +108,17 @@ Transfer properties from this component to a target component that have not alre #### setState ```javascript -setState(object nextState) +setState(object nextState[, function callback]) ``` -Merges nextState with the current state. This is the primary method you use to trigger UI updates from event handlers and server request callbacks. +Merges nextState with the current state. This is the primary method you use to trigger UI updates from event handlers and server request callbacks. In addition, you can supply an optional callback function that is executed once `setState` is completed. **Note:** *NEVER* mutate `this.state` directly. As calling `setState()` afterwards may replace the mutation you made. Treat `this.state` as if it were immutable. **Note:** `setState()` does not immediately mutate `this.state` but creates a pending state transition. Accessing `this.state` after calling this method can potentially return the existing value. +**Note**: There is no guarantee of synchronous operation of calls to `setState` and calls may eventually be batched for performance gains. + #### replaceState ```javascript diff --git a/src/core/ReactComponent.js b/src/core/ReactComponent.js index b9aa2330c49..3353310b1f8 100644 --- a/src/core/ReactComponent.js +++ b/src/core/ReactComponent.js @@ -231,21 +231,23 @@ var ReactComponent = { * Sets a subset of the props. * * @param {object} partialProps Subset of the next props. + * @param {?function} callback Called after props are updated. * @final * @public */ - setProps: function(partialProps) { - this.replaceProps(merge(this.props, partialProps)); + setProps: function(partialProps, callback) { + this.replaceProps(merge(this.props, partialProps), callback); }, /** * Replaces all of the props. * * @param {object} props New props. + * @param {?function} callback Called after props are updated. * @final * @public */ - replaceProps: function(props) { + replaceProps: function(props, callback) { invariant( !this.props[OWNER], 'replaceProps(...): You called `setProps` or `replaceProps` on a ' + @@ -257,6 +259,8 @@ var ReactComponent = { var transaction = ReactComponent.ReactReconcileTransaction.getPooled(); transaction.perform(this.receiveProps, this, props, transaction); ReactComponent.ReactReconcileTransaction.release(transaction); + + callback && callback(); }, /** diff --git a/src/core/ReactCompositeComponent.js b/src/core/ReactCompositeComponent.js index ac2e57d93cb..78041c2a054 100644 --- a/src/core/ReactCompositeComponent.js +++ b/src/core/ReactCompositeComponent.js @@ -525,13 +525,19 @@ var ReactCompositeComponentMixin = { * There is no guarantee that `this.state` will be immediately updated, so * accessing `this.state` after calling this method may return the old value. * + * There is no guarantee that calls to `setState` will run synchronously, + * as they may eventually be batched together. You can provide an optional + * callback that will be executed when the call to setState is actually + * completed. + * * @param {object} partialState Next partial state to be merged with state. + * @param {?function} callback Called after state is updated. * @final * @protected */ - setState: function(partialState) { + setState: function(partialState, callback) { // Merge with `_pendingState` if it exists, otherwise with existing state. - this.replaceState(merge(this._pendingState || this.state, partialState)); + this.replaceState(merge(this._pendingState || this.state, partialState), callback); }, /** @@ -542,10 +548,11 @@ var ReactCompositeComponentMixin = { * accessing `this.state` after calling this method may return the old value. * * @param {object} completeState Next state. + * @param {?function} callback Called after state is updated. * @final * @protected */ - replaceState: function(completeState) { + replaceState: function(completeState, callback) { var compositeLifeCycleState = this._compositeLifeCycleState; invariant( this.isMounted() || @@ -582,6 +589,9 @@ var ReactCompositeComponentMixin = { this._compositeLifeCycleState = null; } + + // If callback is 'truthy', execute it + callback && callback(); }, /** @@ -704,10 +714,11 @@ var ReactCompositeComponentMixin = { * This will not invoke `shouldUpdateComponent`, but it will invoke * `componentWillUpdate` and `componentDidUpdate`. * + * @param {?function} callback Called after update is complete. * @final * @protected */ - forceUpdate: function() { + forceUpdate: function(callback) { var compositeLifeCycleState = this._compositeLifeCycleState; invariant( this.isMounted(), @@ -728,6 +739,8 @@ var ReactCompositeComponentMixin = { transaction ); ReactComponent.ReactReconcileTransaction.release(transaction); + + callback && callback(); }, /**