From a51686b0dbee3b280eac1186b300a7a3d4ed59b7 Mon Sep 17 00:00:00 2001 From: Jim Date: Tue, 7 Apr 2015 14:02:18 -0700 Subject: [PATCH] Switch to parent-based context. Fixes #2112. --- src/core/ReactCompositeComponent.js | 41 +--- .../__tests__/ReactCompositeComponent-test.js | 205 +++--------------- 2 files changed, 35 insertions(+), 211 deletions(-) diff --git a/src/core/ReactCompositeComponent.js b/src/core/ReactCompositeComponent.js index 15afc9952314d..e1f63ffa6a0df 100644 --- a/src/core/ReactCompositeComponent.js +++ b/src/core/ReactCompositeComponent.js @@ -125,7 +125,7 @@ var ReactCompositeComponentMixin = { this._rootNodeID = rootID; var publicProps = this._processProps(this._currentElement.props); - var publicContext = this._processContext(this._currentElement._context); + var publicContext = this._processContext(context); var Component = ReactNativeComponent.getComponentClassForElement( this._currentElement @@ -158,10 +158,6 @@ var ReactCompositeComponentMixin = { // Store a reference from the instance back to the internal representation ReactInstanceMap.set(inst, this); - if (__DEV__) { - this._warnIfContextsDiffer(this._currentElement._context, context); - } - if (__DEV__) { // Since plain JS classes are defined without any special initialization // logic, we can not catch common errors early. Therefore, we have to @@ -529,30 +525,6 @@ var ReactCompositeComponentMixin = { } }, - /** - * Compare two contexts, warning if they are different - * TODO: Remove this check when owner-context is removed - */ - _warnIfContextsDiffer: function(ownerBasedContext, parentBasedContext) { - ownerBasedContext = this._maskContext(ownerBasedContext); - parentBasedContext = this._maskContext(parentBasedContext); - var parentKeys = Object.keys(parentBasedContext).sort(); - var displayName = this.getName() || 'ReactCompositeComponent'; - for (var i = 0; i < parentKeys.length; i++) { - var key = parentKeys[i]; - warning( - ownerBasedContext[key] === parentBasedContext[key], - 'owner-based and parent-based contexts differ ' + - '(values: `%s` vs `%s`) for key (%s) while mounting %s ' + - '(see: http://fb.me/react-context-by-parent)', - ownerBasedContext[key], - parentBasedContext[key], - key, - displayName - ); - } - }, - /** * Perform an update to a mounted component. The componentWillReceiveProps and * shouldComponentUpdate methods are called, then (assuming the update isn't @@ -582,18 +554,9 @@ var ReactCompositeComponentMixin = { // Distinguish between a props update versus a simple state update if (prevParentElement !== nextParentElement) { - nextContext = this._processContext(nextParentElement._context); + nextContext = this._processContext(nextUnmaskedContext); nextProps = this._processProps(nextParentElement.props); - if (__DEV__) { - if (nextUnmaskedContext != null) { - this._warnIfContextsDiffer( - nextParentElement._context, - nextUnmaskedContext - ); - } - } - // 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. diff --git a/src/core/__tests__/ReactCompositeComponent-test.js b/src/core/__tests__/ReactCompositeComponent-test.js index 3b4d3e6ff8e9e..4a5f2e50b3737 100644 --- a/src/core/__tests__/ReactCompositeComponent-test.js +++ b/src/core/__tests__/ReactCompositeComponent-test.js @@ -621,178 +621,6 @@ describe('ReactCompositeComponent', function() { reactComponentExpect(childInstance).scalarContextEqual({foo: 'bar', depth: 0}); }); - it('warn if context keys differ', function() { - var Component = React.createClass({ - contextTypes: { - foo: ReactPropTypes.string.isRequired - }, - - render: function() { - return
; - } - }); - - React.withContext({foo: 'bar'}, function() { - ReactTestUtils.renderIntoDocument(); - }); - - expect(console.error.argsForCall.length).toBe(1); - expect(console.error.argsForCall[0][0]).toBe( - 'Warning: owner-based and parent-based contexts differ ' + - '(values: `bar` vs `undefined`) for key (foo) ' + - 'while mounting Component (see: http://fb.me/react-context-by-parent)' - ); - - }); - - it('warn if context values differ', function() { - var Parent = React.createClass({ - childContextTypes: { - foo: ReactPropTypes.string - }, - - getChildContext: function() { - return { - foo: "bar" - }; - }, - - render: function() { - return
{this.props.children}
; - } - }); - var Component = React.createClass({ - contextTypes: { - foo: ReactPropTypes.string.isRequired - }, - - render: function() { - return
; - } - }); - - var component = React.withContext({foo: 'noise'}, function() { - return ; - }); - - ReactTestUtils.renderIntoDocument({component}); - - // Two warnings, one for the component and one for the div - // We may want to make this expect one warning in the future - expect(console.error.argsForCall.length).toBe(1); - expect(console.error.argsForCall[0][0]).toBe( - 'Warning: owner-based and parent-based contexts differ ' + - '(values: `noise` vs `bar`) for key (foo) while mounting Component ' + - '(see: http://fb.me/react-context-by-parent)' - ); - - }); - - it('should warn if context values differ on update using withContext', function() { - var Parent = React.createClass({ - childContextTypes: { - foo: ReactPropTypes.string - }, - - getChildContext: function() { - return { - foo: "bar" - }; - }, - - render: function() { - return
{this.props.children}
; - } - }); - - var Component = React.createClass({ - contextTypes: { - foo: ReactPropTypes.string.isRequired - }, - - render: function() { - return
; - } - }); - - var div = document.createElement('div'); - - var componentWithSameContext = React.withContext({foo: 'bar'}, function() { - return ; - }); - React.render({componentWithSameContext}, div); - - expect(console.error.argsForCall.length).toBe(0); - - var componentWithDifferentContext = React.withContext({foo: 'noise'}, function() { - return ; - }); - React.render({componentWithDifferentContext}, div); - - // Two warnings, one for the component and one for the div - // We may want to make this expect one warning in the future - expect(console.error.argsForCall.length).toBe(1); - expect(console.error.argsForCall[0][0]).toBe( - 'Warning: owner-based and parent-based contexts differ ' + - '(values: `noise` vs `bar`) for key (foo) while mounting Component ' + - '(see: http://fb.me/react-context-by-parent)' - ); - }); - - it('should warn if context values differ on update using wrapper', function() { - var Parent = React.createClass({ - childContextTypes: { - foo: ReactPropTypes.string - }, - - getChildContext: function() { - return { - foo: "bar" - }; - }, - - render: function() { - return
{this.props.children}
; - } - }); - - var Component = React.createClass({ - contextTypes: { - foo: ReactPropTypes.string.isRequired - }, - - render: function() { - return
; - } - }); - - var Wrapper = React.createClass({ - childContextTypes: { - foo: ReactPropTypes.string - }, - - getChildContext: function() { - return {foo: this.props.foo}; - }, - - render: function() { return ; } - - }); - - var div = document.createElement('div'); - React.render(, div); - React.render(, div); - - // Two warnings, one for the component and one for the div - // We may want to make this expect one warning in the future - expect(console.error.argsForCall.length).toBe(1); - expect(console.error.argsForCall[0][0]).toBe( - 'Warning: owner-based and parent-based contexts differ ' + - '(values: `noise` vs `bar`) for key (foo) while mounting Component ' + - '(see: http://fb.me/react-context-by-parent)' - ); - }); - it('unmasked context propagates through updates', function() { var Leaf = React.createClass({ @@ -996,4 +824,37 @@ describe('ReactCompositeComponent', function() { ); }); + it('context should be passed down from the parent', function() { + var Parent = React.createClass({ + childContextTypes: { + foo: ReactPropTypes.string + }, + + getChildContext: function() { + return { + foo: "bar" + }; + }, + + render: function() { + return
{this.props.children}
; + } + }); + + var Component = React.createClass({ + contextTypes: { + foo: ReactPropTypes.string.isRequired + }, + + render: function() { + return
; + } + }); + + var div = document.createElement('div'); + React.render(, div); + + expect(console.error.argsForCall.length).toBe(0); + }); + });