diff --git a/src/renderers/shared/reconciler/ReactCompositeComponent.js b/src/renderers/shared/reconciler/ReactCompositeComponent.js index 612bf5fd34035..45401f499a82a 100644 --- a/src/renderers/shared/reconciler/ReactCompositeComponent.js +++ b/src/renderers/shared/reconciler/ReactCompositeComponent.js @@ -647,12 +647,18 @@ var ReactCompositeComponentMixin = { nextUnmaskedContext ) { var inst = this._instance; - - var nextContext = this._context === nextUnmaskedContext ? - inst.context : - this._processContext(nextUnmaskedContext); + var willReceive = false; + var nextContext; var nextProps; + // Determine if the context has changed or not + if (this._context === nextUnmaskedContext) { + nextContext = inst.context; + } else { + nextContext = this._processContext(nextUnmaskedContext); + willReceive = true; + } + // Distinguish between a props update versus a simple state update if (prevParentElement === nextParentElement) { // Skip checking prop types again -- we don't read inst.props to avoid @@ -660,13 +666,14 @@ var ReactCompositeComponentMixin = { nextProps = nextParentElement.props; } else { nextProps = this._processProps(nextParentElement.props); - // An update here will schedule an update but immediately set - // _pendingStateQueue which will ensure that any state updates gets - // immediately reconciled instead of waiting for the next batch. + willReceive = true; + } - if (inst.componentWillReceiveProps) { - inst.componentWillReceiveProps(nextProps, nextContext); - } + // An update here will schedule an update but immediately set + // _pendingStateQueue which will ensure that any state updates gets + // immediately reconciled instead of waiting for the next batch. + if (willReceive && inst.componentWillReceiveProps) { + inst.componentWillReceiveProps(nextProps, nextContext); } var nextState = this._processPendingState(nextProps, nextContext); diff --git a/src/renderers/shared/reconciler/__tests__/ReactCompositeComponent-test.js b/src/renderers/shared/reconciler/__tests__/ReactCompositeComponent-test.js index 17f8ba963af6c..0bcb65149189a 100644 --- a/src/renderers/shared/reconciler/__tests__/ReactCompositeComponent-test.js +++ b/src/renderers/shared/reconciler/__tests__/ReactCompositeComponent-test.js @@ -874,6 +874,123 @@ describe('ReactCompositeComponent', function() { expect(div.children[0].id).toBe('aliens'); }); + it('should trigger componentWillReceiveProps for context changes', function() { + var contextChanges = 0; + var propChanges = 0; + + var GrandChild = React.createClass({ + contextTypes: { + foo: ReactPropTypes.string.isRequired, + }, + + componentWillReceiveProps: function(nextProps, nextContext) { + expect('foo' in nextContext).toBe(true); + + if (nextProps !== this.props) { + propChanges++; + } + + if (nextContext !== this.context) { + contextChanges++; + } + }, + + render: function() { + return {this.props.children}; + }, + }); + + var ChildWithContext = React.createClass({ + contextTypes: { + foo: ReactPropTypes.string.isRequired, + }, + + componentWillReceiveProps: function(nextProps, nextContext) { + expect('foo' in nextContext).toBe(true); + + if (nextProps !== this.props) { + propChanges++; + } + + if (nextContext !== this.context) { + contextChanges++; + } + }, + + render: function() { + return