diff --git a/scripts/fiber/tests-failing.txt b/scripts/fiber/tests-failing.txt
index 92ac48f24ed..bcd6e684cf6 100644
--- a/scripts/fiber/tests-failing.txt
+++ b/scripts/fiber/tests-failing.txt
@@ -19,8 +19,7 @@ src/addons/transitions/__tests__/ReactCSSTransitionGroup-test.js
* should transition from false to one
src/isomorphic/classic/__tests__/ReactContextValidator-test.js
-* should filter out context not in contextTypes
-* should filter context properly in callbacks
+* should pass previous context to lifecycles
src/isomorphic/classic/class/__tests__/ReactBind-test.js
* Holds reference to instance
@@ -31,24 +30,9 @@ src/isomorphic/classic/class/__tests__/ReactBindOptout-test.js
* works with mixins that have not opted out of autobinding
* works with mixins that have opted out of autobinding
-src/isomorphic/classic/class/__tests__/ReactClass-test.js
-* renders based on context getInitialState
-
src/isomorphic/classic/element/__tests__/ReactElementValidator-test.js
* includes the owner name when passing null, undefined, boolean, or number
-src/isomorphic/modern/class/__tests__/ReactCoffeeScriptClass-test.coffee
-* renders based on context in the constructor
-* supports this.context passed via getChildContext
-
-src/isomorphic/modern/class/__tests__/ReactES6Class-test.js
-* renders based on context in the constructor
-* supports this.context passed via getChildContext
-
-src/isomorphic/modern/class/__tests__/ReactTypeScriptClass-test.ts
-* renders based on context in the constructor
-* supports this.context passed via getChildContext
-
src/isomorphic/modern/element/__tests__/ReactJSXElementValidator-test.js
* should give context for PropType errors in nested components.
@@ -441,13 +425,6 @@ src/renderers/shared/stack/reconciler/__tests__/ReactCompositeComponent-test.js
* should warn about `setState` on unmounted components
* should warn about `setState` in render
* should warn about `setState` in getChildContext
-* should pass context to children when not owner
-* should pass context when re-rendered for static child
-* should pass context when re-rendered for static child within a composite component
-* should pass context transitively
-* should pass context when re-rendered
-* unmasked context propagates through updates
-* should trigger componentWillReceiveProps for context changes
* should update refs if shouldComponentUpdate gives false
* should support objects with prototypes as state
@@ -467,10 +444,8 @@ src/renderers/shared/stack/reconciler/__tests__/ReactMultiChildText-test.js
* should throw if rendering both HTML and children
src/renderers/shared/stack/reconciler/__tests__/ReactStatelessComponent-test.js
-* should pass context thru stateless component
* should warn when stateless component returns array
* should throw on string refs in pure functions
-* should receive context
* should warn when using non-React functions in JSX
src/renderers/shared/stack/reconciler/__tests__/ReactUpdates-test.js
diff --git a/scripts/fiber/tests-passing-except-dev.txt b/scripts/fiber/tests-passing-except-dev.txt
index 501853cc570..50d2a933219 100644
--- a/scripts/fiber/tests-passing-except-dev.txt
+++ b/scripts/fiber/tests-passing-except-dev.txt
@@ -12,9 +12,6 @@ src/isomorphic/classic/element/__tests__/ReactElementValidator-test.js
* warns for keys with component stack info
* should give context for PropType errors in nested components.
-src/isomorphic/modern/element/__tests__/ReactJSXElementValidator-test.js
-* should warn on invalid context types
-
src/renderers/dom/shared/__tests__/CSSPropertyOperations-test.js
* should warn when using hyphenated style names
* should warn when updating hyphenated style names
diff --git a/scripts/fiber/tests-passing.txt b/scripts/fiber/tests-passing.txt
index b5c82a50dbb..9c2105a8ef9 100644
--- a/scripts/fiber/tests-passing.txt
+++ b/scripts/fiber/tests-passing.txt
@@ -128,6 +128,10 @@ src/isomorphic/children/__tests__/sliceChildren-test.js
* should allow static children to be sliced
* should slice nested children
+src/isomorphic/classic/__tests__/ReactContextValidator-test.js
+* should filter out context not in contextTypes
+* should pass next context to lifecycles
+
src/isomorphic/classic/class/__tests__/ReactBind-test.js
* warns if you try to bind to this
* does not warn if you pass an auto-bound method to setState
@@ -149,6 +153,7 @@ src/isomorphic/classic/class/__tests__/ReactClass-test.js
* should throw if a reserved property is in statics
* should support statics
* should work with object getInitialState() return values
+* renders based on context getInitialState
* should throw with non-object getInitialState() return values
* should work with a null getInitialState() return value
* should throw when using legacy factories
@@ -354,6 +359,7 @@ src/isomorphic/modern/class/__tests__/ReactCoffeeScriptClass-test.coffee
* renders a simple stateless component with prop
* renders based on state using initial values in this.props
* renders based on state using props in the constructor
+* renders based on context in the constructor
* renders only once when setting state in componentWillMount
* should throw with non-object in the initial state property
* should render with null in the initial state property
@@ -365,6 +371,7 @@ src/isomorphic/modern/class/__tests__/ReactCoffeeScriptClass-test.coffee
* should warn when misspelling shouldComponentUpdate
* should warn when misspelling componentWillReceiveProps
* should throw AND warn when trying to access classic APIs
+* supports this.context passed via getChildContext
* supports classic refs
* supports drilling through to the DOM using findDOMNode
@@ -374,6 +381,7 @@ src/isomorphic/modern/class/__tests__/ReactES6Class-test.js
* renders a simple stateless component with prop
* renders based on state using initial values in this.props
* renders based on state using props in the constructor
+* renders based on context in the constructor
* renders only once when setting state in componentWillMount
* should throw with non-object in the initial state property
* should render with null in the initial state property
@@ -385,6 +393,7 @@ src/isomorphic/modern/class/__tests__/ReactES6Class-test.js
* should warn when misspelling shouldComponentUpdate
* should warn when misspelling componentWillReceiveProps
* should throw AND warn when trying to access classic APIs
+* supports this.context passed via getChildContext
* supports classic refs
* supports drilling through to the DOM using findDOMNode
@@ -399,6 +408,7 @@ src/isomorphic/modern/class/__tests__/ReactTypeScriptClass-test.ts
* renders a simple stateless component with prop
* renders based on state using initial values in this.props
* renders based on state using props in the constructor
+* renders based on context in the constructor
* renders only once when setting state in componentWillMount
* should throw with non-object in the initial state property
* should render with null in the initial state property
@@ -410,6 +420,7 @@ src/isomorphic/modern/class/__tests__/ReactTypeScriptClass-test.ts
* should warn when misspelling shouldComponentUpdate
* should warn when misspelling componentWillReceiveProps
* should throw AND warn when trying to access classic APIs
+* supports this.context passed via getChildContext
* supports classic refs
* supports drilling through to the DOM using findDOMNode
@@ -446,6 +457,7 @@ src/isomorphic/modern/element/__tests__/ReactJSXElementValidator-test.js
* should not check the default for explicit null
* should check declared prop types
* should warn on invalid prop types
+* should warn on invalid context types
* should warn if getDefaultProps is specificed on the class
src/renderers/dom/__tests__/ReactDOMProduction-test.js
@@ -806,6 +818,11 @@ src/renderers/shared/fiber/__tests__/ReactIncremental-test.js
* performs batched updates at the end of the batch
* can nest batchedUpdates
* can handle if setState callback throws
+* merges and masks context
+* does not leak own context into context provider
+* provides context when reusing work
+* reads context when setState is below the provider
+* reads context when setState is above the provider
src/renderers/shared/fiber/__tests__/ReactIncrementalErrorHandling-test.js
* catches render error in a boundary during mounting
@@ -1018,7 +1035,14 @@ src/renderers/shared/stack/reconciler/__tests__/ReactCompositeComponent-test.js
* should call componentWillUnmount before unmounting
* should warn when shouldComponentUpdate() returns undefined
* should warn when componentDidUnmount method is defined
+* should pass context to children when not owner
* should skip update when rerendering element in container
+* should pass context when re-rendered for static child
+* should pass context when re-rendered for static child within a composite component
+* should pass context transitively
+* should pass context when re-rendered
+* unmasked context propagates through updates
+* should trigger componentWillReceiveProps for context changes
* only renders once if updated in componentWillReceiveProps
* should allow access to findDOMNode in componentWillUnmount
* context should be passed down from the parent
@@ -1147,9 +1171,11 @@ src/renderers/shared/stack/reconciler/__tests__/ReactStatelessComponent-test.js
* should render stateless component
* should update stateless component
* should unmount stateless component
+* should pass context thru stateless component
* should provide a null ref
* should use correct name in key warning
* should support default props and prop types
+* should receive context
* should work with arrow functions
* should allow simple functions to return null
* should allow simple functions to return false
diff --git a/src/isomorphic/classic/__tests__/ReactContextValidator-test.js b/src/isomorphic/classic/__tests__/ReactContextValidator-test.js
index 6e237e65379..844a9e80269 100644
--- a/src/isomorphic/classic/__tests__/ReactContextValidator-test.js
+++ b/src/isomorphic/classic/__tests__/ReactContextValidator-test.js
@@ -70,11 +70,10 @@ describe('ReactContextValidator', () => {
expect(instance.refs.child.context).toEqual({foo: 'abc'});
});
- it('should filter context properly in callbacks', () => {
+ it('should pass next context to lifecycles', () => {
var actualComponentWillReceiveProps;
var actualShouldComponentUpdate;
var actualComponentWillUpdate;
- var actualComponentDidUpdate;
var Parent = React.createClass({
childContextTypes: {
@@ -113,6 +112,45 @@ describe('ReactContextValidator', () => {
actualComponentWillUpdate = nextContext;
},
+ render: function() {
+ return
;
+ },
+ });
+
+ var container = document.createElement('div');
+ ReactDOM.render(, container);
+ ReactDOM.render(, container);
+ expect(actualComponentWillReceiveProps).toEqual({foo: 'def'});
+ expect(actualShouldComponentUpdate).toEqual({foo: 'def'});
+ expect(actualComponentWillUpdate).toEqual({foo: 'def'});
+ });
+
+ it('should pass previous context to lifecycles', () => {
+ var actualComponentDidUpdate;
+
+ var Parent = React.createClass({
+ childContextTypes: {
+ foo: React.PropTypes.string.isRequired,
+ bar: React.PropTypes.string.isRequired,
+ },
+
+ getChildContext: function() {
+ return {
+ foo: this.props.foo,
+ bar: 'bar',
+ };
+ },
+
+ render: function() {
+ return ;
+ },
+ });
+
+ var Component = React.createClass({
+ contextTypes: {
+ foo: React.PropTypes.string,
+ },
+
componentDidUpdate: function(prevProps, prevState, prevContext) {
actualComponentDidUpdate = prevContext;
},
@@ -125,9 +163,6 @@ describe('ReactContextValidator', () => {
var container = document.createElement('div');
ReactDOM.render(, container);
ReactDOM.render(, container);
- expect(actualComponentWillReceiveProps).toEqual({foo: 'def'});
- expect(actualShouldComponentUpdate).toEqual({foo: 'def'});
- expect(actualComponentWillUpdate).toEqual({foo: 'def'});
expect(actualComponentDidUpdate).toEqual({foo: 'abc'});
});
diff --git a/src/renderers/shared/fiber/ReactFiberBeginWork.js b/src/renderers/shared/fiber/ReactFiberBeginWork.js
index b35567478c7..02fd265aa93 100644
--- a/src/renderers/shared/fiber/ReactFiberBeginWork.js
+++ b/src/renderers/shared/fiber/ReactFiberBeginWork.js
@@ -23,7 +23,15 @@ var {
reconcileChildFibersInPlace,
cloneChildFibers,
} = require('ReactChildFiber');
+
var ReactTypeOfWork = require('ReactTypeOfWork');
+var {
+ getMaskedContext,
+ isContextProvider,
+ hasContextChanged,
+ pushContextProvider,
+ resetContext,
+} = require('ReactFiberContext');
var {
IndeterminateComponent,
FunctionalComponent,
@@ -144,6 +152,7 @@ module.exports = function(
function updateFunctionalComponent(current, workInProgress) {
var fn = workInProgress.type;
var props = workInProgress.pendingProps;
+ var context = getMaskedContext(workInProgress);
// TODO: Disable this before release, since it is not part of the public API
// I use this for testing to compare the relative overhead of classes.
@@ -159,9 +168,9 @@ module.exports = function(
if (__DEV__) {
ReactCurrentOwner.current = workInProgress;
- nextChildren = fn(props);
+ nextChildren = fn(props, context);
} else {
- nextChildren = fn(props);
+ nextChildren = fn(props, context);
}
reconcileChildren(current, workInProgress, nextChildren);
return workInProgress.child;
@@ -190,6 +199,10 @@ module.exports = function(
ReactCurrentOwner.current = workInProgress;
const nextChildren = instance.render();
reconcileChildren(current, workInProgress, nextChildren);
+ // Put context on the stack because we will work on children
+ if (isContextProvider(workInProgress)) {
+ pushContextProvider(workInProgress, true);
+ }
return workInProgress.child;
}
@@ -249,13 +262,15 @@ module.exports = function(
}
var fn = workInProgress.type;
var props = workInProgress.pendingProps;
+ var context = getMaskedContext(workInProgress);
+
var value;
if (__DEV__) {
ReactCurrentOwner.current = workInProgress;
- value = fn(props);
+ value = fn(props, context);
} else {
- value = fn(props);
+ value = fn(props, context);
}
if (typeof value === 'object' && value && typeof value.render === 'function') {
@@ -345,6 +360,10 @@ module.exports = function(
cloneChildFibers(current, workInProgress);
markChildAsProgressed(current, workInProgress, priorityLevel);
+ // Put context on the stack because we will work on children
+ if (isContextProvider(workInProgress)) {
+ pushContextProvider(workInProgress, false);
+ }
return workInProgress.child;
}
@@ -355,6 +374,11 @@ module.exports = function(
}
function beginWork(current : ?Fiber, workInProgress : Fiber, priorityLevel : PriorityLevel) : ?Fiber {
+ if (!workInProgress.return) {
+ // Don't start new work with context on the stack.
+ resetContext();
+ }
+
if (workInProgress.pendingWorkPriority === NoWork ||
workInProgress.pendingWorkPriority > priorityLevel) {
return bailoutOnLowPriority(current, workInProgress);
@@ -375,7 +399,8 @@ module.exports = function(
workInProgress.memoizedProps !== null &&
workInProgress.pendingProps === workInProgress.memoizedProps
)) &&
- workInProgress.updateQueue === null) {
+ workInProgress.updateQueue === null &&
+ !hasContextChanged()) {
return bailoutOnAlreadyFinishedWork(current, workInProgress);
}
diff --git a/src/renderers/shared/fiber/ReactFiberClassComponent.js b/src/renderers/shared/fiber/ReactFiberClassComponent.js
index fb8a0352fa2..79a6a9ebc9e 100644
--- a/src/renderers/shared/fiber/ReactFiberClassComponent.js
+++ b/src/renderers/shared/fiber/ReactFiberClassComponent.js
@@ -15,19 +15,21 @@
import type { Fiber } from 'ReactFiber';
import type { UpdateQueue } from 'ReactFiberUpdateQueue';
+var {
+ getMaskedContext,
+} = require('ReactFiberContext');
var {
createUpdateQueue,
addToQueue,
addCallbackToQueue,
mergeUpdateQueue,
} = require('ReactFiberUpdateQueue');
-var { isMounted } = require('ReactFiberTreeReflection');
+var { getComponentName, isMounted } = require('ReactFiberTreeReflection');
var ReactInstanceMap = require('ReactInstanceMap');
var shallowEqual = require('shallowEqual');
var warning = require('warning');
var invariant = require('invariant');
-
const isArray = Array.isArray;
module.exports = function(scheduleUpdate : (fiber: Fiber) => void) {
@@ -74,7 +76,7 @@ module.exports = function(scheduleUpdate : (fiber: Fiber) => void) {
},
};
- function checkShouldComponentUpdate(workInProgress, oldProps, newProps, newState) {
+ function checkShouldComponentUpdate(workInProgress, oldProps, newProps, newState, newContext) {
const updateQueue = workInProgress.updateQueue;
if (oldProps === null || (updateQueue && updateQueue.isForced)) {
return true;
@@ -82,14 +84,14 @@ module.exports = function(scheduleUpdate : (fiber: Fiber) => void) {
const instance = workInProgress.stateNode;
if (typeof instance.shouldComponentUpdate === 'function') {
- const shouldUpdate = instance.shouldComponentUpdate(newProps, newState);
+ const shouldUpdate = instance.shouldComponentUpdate(newProps, newState, newContext);
if (__DEV__) {
warning(
shouldUpdate !== undefined,
'%s.shouldComponentUpdate(): Returned undefined instead of a ' +
'boolean value. Make sure to return true or false.',
- getName(workInProgress, instance)
+ getComponentName(workInProgress)
);
}
@@ -107,20 +109,11 @@ module.exports = function(scheduleUpdate : (fiber: Fiber) => void) {
return true;
}
- function getName(workInProgress: Fiber, inst: any): string {
- const type = workInProgress.type;
- const constructor = inst && inst.constructor;
- return (
- type.displayName || (constructor && constructor.displayName) ||
- type.name || (constructor && constructor.name) ||
- 'A Component'
- );
- }
-
- function checkClassInstance(workInProgress: Fiber, inst: any) {
+ function checkClassInstance(workInProgress: Fiber) {
+ const instance = workInProgress.stateNode;
if (__DEV__) {
- const name = getName(workInProgress, inst);
- const renderPresent = inst.render;
+ const name = getComponentName(workInProgress);
+ const renderPresent = instance.render;
warning(
renderPresent,
'%s(...): No `render` method found on the returned component ' +
@@ -128,8 +121,8 @@ module.exports = function(scheduleUpdate : (fiber: Fiber) => void) {
name
);
const noGetInitialStateOnES6 = (
- !inst.getInitialState ||
- inst.getInitialState.isReactClassApproved
+ !instance.getInitialState ||
+ instance.getInitialState.isReactClassApproved
);
warning(
noGetInitialStateOnES6,
@@ -139,8 +132,8 @@ module.exports = function(scheduleUpdate : (fiber: Fiber) => void) {
name
);
const noGetDefaultPropsOnES6 = (
- !inst.getDefaultProps ||
- inst.getDefaultProps.isReactClassApproved
+ !instance.getDefaultProps ||
+ instance.getDefaultProps.isReactClassApproved
);
warning(
noGetDefaultPropsOnES6,
@@ -149,21 +142,21 @@ module.exports = function(scheduleUpdate : (fiber: Fiber) => void) {
'Use a static property to define defaultProps instead.',
name
);
- const noInstancePropTypes = !inst.propTypes;
+ const noInstancePropTypes = !instance.propTypes;
warning(
noInstancePropTypes,
'propTypes was defined as an instance property on %s. Use a static ' +
'property to define propTypes instead.',
name,
);
- const noInstanceContextTypes = !inst.contextTypes;
+ const noInstanceContextTypes = !instance.contextTypes;
warning(
noInstanceContextTypes,
'contextTypes was defined as an instance property on %s. Use a static ' +
'property to define contextTypes instead.',
name,
);
- const noComponentShouldUpdate = typeof inst.componentShouldUpdate !== 'function';
+ const noComponentShouldUpdate = typeof instance.componentShouldUpdate !== 'function';
warning(
noComponentShouldUpdate,
'%s has a method called ' +
@@ -172,7 +165,7 @@ module.exports = function(scheduleUpdate : (fiber: Fiber) => void) {
'expected to return a value.',
name
);
- const noComponentDidUnmount = typeof inst.componentDidUnmount !== 'function';
+ const noComponentDidUnmount = typeof instance.componentDidUnmount !== 'function';
warning(
noComponentDidUnmount,
'%s has a method called ' +
@@ -180,7 +173,7 @@ module.exports = function(scheduleUpdate : (fiber: Fiber) => void) {
'Did you mean componentWillUnmount()?',
name
);
- const noComponentWillRecieveProps = typeof inst.componentWillRecieveProps !== 'function';
+ const noComponentWillRecieveProps = typeof instance.componentWillRecieveProps !== 'function';
warning(
noComponentWillRecieveProps,
'%s has a method called ' +
@@ -189,12 +182,20 @@ module.exports = function(scheduleUpdate : (fiber: Fiber) => void) {
);
}
- const instanceState = inst.state;
- if (instanceState && (typeof instanceState !== 'object' || isArray(instanceState))) {
+ const state = instance.state;
+ if (state && (typeof state !== 'object' || isArray(state))) {
invariant(
false,
'%s.state: must be set to an object or null',
- getName(workInProgress, inst)
+ getComponentName(workInProgress)
+ );
+ }
+ if (typeof instance.getChildContext === 'function') {
+ invariant(
+ typeof workInProgress.type.childContextTypes === 'object',
+ '%s.getChildContext(): childContextTypes must be defined in order to ' +
+ 'use getChildContext().',
+ getComponentName(workInProgress)
);
}
}
@@ -209,16 +210,16 @@ module.exports = function(scheduleUpdate : (fiber: Fiber) => void) {
function constructClassInstance(workInProgress : Fiber) : any {
const ctor = workInProgress.type;
const props = workInProgress.pendingProps;
- const instance = new ctor(props);
- checkClassInstance(workInProgress, instance);
+ const context = getMaskedContext(workInProgress);
+ const instance = new ctor(props, context);
adoptClassInstance(workInProgress, instance);
+ checkClassInstance(workInProgress);
return instance;
}
// Invokes the mount life-cycles on a previously never rendered instance.
function mountClassInstance(workInProgress : Fiber) : void {
const instance = workInProgress.stateNode;
-
const state = instance.state || null;
let props = workInProgress.pendingProps;
@@ -228,6 +229,7 @@ module.exports = function(scheduleUpdate : (fiber: Fiber) => void) {
instance.props = props;
instance.state = state;
+ instance.context = getMaskedContext(workInProgress);
if (typeof instance.componentWillMount === 'function') {
instance.componentWillMount();
@@ -253,6 +255,7 @@ module.exports = function(scheduleUpdate : (fiber: Fiber) => void) {
throw new Error('There should always be pending or memoized props.');
}
}
+ const newContext = getMaskedContext(workInProgress);
// TODO: Should we deal with a setState that happened after the last
// componentWillMount and before this componentWillMount? Probably
@@ -262,7 +265,8 @@ module.exports = function(scheduleUpdate : (fiber: Fiber) => void) {
workInProgress,
workInProgress.memoizedProps,
newProps,
- newState
+ newState,
+ newContext
)) {
return false;
}
@@ -272,6 +276,7 @@ module.exports = function(scheduleUpdate : (fiber: Fiber) => void) {
const newInstance = constructClassInstance(workInProgress);
newInstance.props = newProps;
newInstance.state = newState = newInstance.state || null;
+ newInstance.context = getMaskedContext(workInProgress);
if (typeof newInstance.componentWillMount === 'function') {
newInstance.componentWillMount();
@@ -300,34 +305,37 @@ module.exports = function(scheduleUpdate : (fiber: Fiber) => void) {
throw new Error('There should always be pending or memoized props.');
}
}
+ const oldContext = instance.context;
+ const newContext = getMaskedContext(workInProgress);
// Note: During these life-cycles, instance.props/instance.state are what
// ever the previously attempted to render - not the "current". However,
// during componentDidUpdate we pass the "current" props.
- if (oldProps !== newProps) {
+ if (oldProps !== newProps || oldContext !== newContext) {
if (typeof instance.componentWillReceiveProps === 'function') {
- instance.componentWillReceiveProps(newProps);
+ instance.componentWillReceiveProps(newProps, newContext);
}
}
// Compute the next state using the memoized state and the update queue.
const updateQueue = workInProgress.updateQueue;
- const previousState = workInProgress.memoizedState;
+ const oldState = workInProgress.memoizedState;
// TODO: Previous state can be null.
let newState;
if (updateQueue) {
if (!updateQueue.hasUpdate) {
- newState = previousState;
+ newState = oldState;
} else {
- newState = mergeUpdateQueue(updateQueue, instance, previousState, newProps);
+ newState = mergeUpdateQueue(updateQueue, instance, oldState, newProps);
}
} else {
- newState = previousState;
+ newState = oldState;
}
if (oldProps === newProps &&
- previousState === newState &&
+ oldState === newState &&
+ oldContext === newContext &&
updateQueue && !updateQueue.isForced) {
return false;
}
@@ -336,18 +344,20 @@ module.exports = function(scheduleUpdate : (fiber: Fiber) => void) {
workInProgress,
oldProps,
newProps,
- newState
+ newState,
+ newContext
)) {
// TODO: Should this get the new props/state updated regardless?
return false;
}
if (typeof instance.componentWillUpdate === 'function') {
- instance.componentWillUpdate(newProps, newState);
+ instance.componentWillUpdate(newProps, newState, newContext);
}
instance.props = newProps;
instance.state = newState;
+ instance.context = newContext;
return true;
}
diff --git a/src/renderers/shared/fiber/ReactFiberCompleteWork.js b/src/renderers/shared/fiber/ReactFiberCompleteWork.js
index b0eea7c87e2..82a9bdf211a 100644
--- a/src/renderers/shared/fiber/ReactFiberCompleteWork.js
+++ b/src/renderers/shared/fiber/ReactFiberCompleteWork.js
@@ -18,6 +18,10 @@ import type { HostConfig } from 'ReactFiberReconciler';
import type { ReifiedYield } from 'ReactReifiedYield';
var { reconcileChildFibers } = require('ReactChildFiber');
+var {
+ isContextProvider,
+ popContextProvider,
+} = require('ReactFiberContext');
var ReactTypeOfWork = require('ReactTypeOfWork');
var ReactTypeOfSideEffect = require('ReactTypeOfSideEffect');
var {
@@ -125,6 +129,10 @@ module.exports = function(config : HostConfig) {
return null;
case ClassComponent:
transferOutput(workInProgress.child, workInProgress);
+ // We are leaving this subtree, so pop context if any.
+ if (isContextProvider(workInProgress)) {
+ popContextProvider();
+ }
// Don't use the state queue to compute the memoized state. We already
// merged it and assigned it to the instance. Transfer it from there.
// Also need to transfer the props, because pendingProps will be null
diff --git a/src/renderers/shared/fiber/ReactFiberContext.js b/src/renderers/shared/fiber/ReactFiberContext.js
new file mode 100644
index 00000000000..d2e09311abc
--- /dev/null
+++ b/src/renderers/shared/fiber/ReactFiberContext.js
@@ -0,0 +1,117 @@
+/**
+ * Copyright 2013-present, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactFiberContext
+ * @flow
+ */
+
+'use strict';
+
+import type { Fiber } from 'ReactFiber';
+
+var emptyObject = require('emptyObject');
+var invariant = require('invariant');
+var {
+ getComponentName,
+} = require('ReactFiberTreeReflection');
+var {
+ ClassComponent,
+} = require('ReactTypeOfWork');
+
+if (__DEV__) {
+ var checkReactTypeSpec = require('checkReactTypeSpec');
+}
+
+let index = -1;
+const contextStack : Array