From eedca6f641d2ea52fb1de5f12f61bc21b7c5f0d6 Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Mon, 14 Nov 2016 18:24:30 +0000 Subject: [PATCH] Disable memoized props bailout when context might have changed --- scripts/fiber/tests-failing.txt | 2 -- scripts/fiber/tests-passing.txt | 2 ++ .../shared/fiber/ReactFiberBeginWork.js | 8 +++++--- src/renderers/shared/fiber/ReactFiberContext.js | 17 ++++++++++++----- 4 files changed, 19 insertions(+), 10 deletions(-) diff --git a/scripts/fiber/tests-failing.txt b/scripts/fiber/tests-failing.txt index 3367df108b..af870d39a1 100644 --- a/scripts/fiber/tests-failing.txt +++ b/scripts/fiber/tests-failing.txt @@ -425,8 +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 when re-rendered for static child -* should pass context when re-rendered for static child within a composite component * unmasked context propagates through updates * should trigger componentWillReceiveProps for context changes * should update refs if shouldComponentUpdate gives false diff --git a/scripts/fiber/tests-passing.txt b/scripts/fiber/tests-passing.txt index bae9086652..c763f784ea 100644 --- a/scripts/fiber/tests-passing.txt +++ b/scripts/fiber/tests-passing.txt @@ -1035,6 +1035,8 @@ src/renderers/shared/stack/reconciler/__tests__/ReactCompositeComponent-test.js * 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 * only renders once if updated in componentWillReceiveProps diff --git a/src/renderers/shared/fiber/ReactFiberBeginWork.js b/src/renderers/shared/fiber/ReactFiberBeginWork.js index 155f951b61..02fd265aa9 100644 --- a/src/renderers/shared/fiber/ReactFiberBeginWork.js +++ b/src/renderers/shared/fiber/ReactFiberBeginWork.js @@ -28,6 +28,7 @@ var ReactTypeOfWork = require('ReactTypeOfWork'); var { getMaskedContext, isContextProvider, + hasContextChanged, pushContextProvider, resetContext, } = require('ReactFiberContext'); @@ -200,7 +201,7 @@ module.exports = function( reconcileChildren(current, workInProgress, nextChildren); // Put context on the stack because we will work on children if (isContextProvider(workInProgress)) { - pushContextProvider(workInProgress); + pushContextProvider(workInProgress, true); } return workInProgress.child; } @@ -361,7 +362,7 @@ module.exports = function( markChildAsProgressed(current, workInProgress, priorityLevel); // Put context on the stack because we will work on children if (isContextProvider(workInProgress)) { - pushContextProvider(workInProgress); + pushContextProvider(workInProgress, false); } return workInProgress.child; } @@ -398,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/ReactFiberContext.js b/src/renderers/shared/fiber/ReactFiberContext.js index eeb78e4f30..fbc478020f 100644 --- a/src/renderers/shared/fiber/ReactFiberContext.js +++ b/src/renderers/shared/fiber/ReactFiberContext.js @@ -28,13 +28,14 @@ if (__DEV__) { } let index = -1; -const stack = []; +const contextStack : Array = []; +const didPerformWorkStack : Array = []; function getUnmaskedContext() { if (index === -1) { return emptyObject; } - return stack[index]; + return contextStack[index]; } exports.getMaskedContext = function(fiber : Fiber) { @@ -59,6 +60,10 @@ exports.getMaskedContext = function(fiber : Fiber) { return context; }; +exports.hasContextChanged = function() : boolean { + return index > -1 && didPerformWorkStack[index]; +}; + exports.isContextProvider = function(fiber : Fiber) : boolean { return ( fiber.tag === ClassComponent && @@ -67,11 +72,12 @@ exports.isContextProvider = function(fiber : Fiber) : boolean { }; exports.popContextProvider = function() : void { - stack[index] = emptyObject; + contextStack[index] = emptyObject; + didPerformWorkStack[index] = false; index--; }; -exports.pushContextProvider = function(fiber : Fiber) : void { +exports.pushContextProvider = function(fiber : Fiber, didPerformWork : boolean) : void { const instance = fiber.stateNode; const childContextTypes = fiber.type.childContextTypes; const childContext = instance.getChildContext(); @@ -92,7 +98,8 @@ exports.pushContextProvider = function(fiber : Fiber) : void { const mergedContext = Object.assign({}, getUnmaskedContext(), childContext); index++; - stack[index] = mergedContext; + contextStack[index] = mergedContext; + didPerformWorkStack[index] = didPerformWork; }; exports.resetContext = function() : void {