Disable memoized props bailout when context might have changed

This commit is contained in:
Dan Abramov
2016-11-14 18:24:32 +00:00
parent 56e1c126c5
commit eedca6f641
4 changed files with 19 additions and 10 deletions
-2
View File
@@ -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
+2
View File
@@ -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
@@ -28,6 +28,7 @@ var ReactTypeOfWork = require('ReactTypeOfWork');
var {
getMaskedContext,
isContextProvider,
hasContextChanged,
pushContextProvider,
resetContext,
} = require('ReactFiberContext');
@@ -200,7 +201,7 @@ module.exports = function<T, P, I, TI, C>(
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<T, P, I, TI, C>(
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<T, P, I, TI, C>(
workInProgress.memoizedProps !== null &&
workInProgress.pendingProps === workInProgress.memoizedProps
)) &&
workInProgress.updateQueue === null) {
workInProgress.updateQueue === null &&
!hasContextChanged()) {
return bailoutOnAlreadyFinishedWork(current, workInProgress);
}
@@ -28,13 +28,14 @@ if (__DEV__) {
}
let index = -1;
const stack = [];
const contextStack : Array<Object> = [];
const didPerformWorkStack : Array<boolean> = [];
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 {