Disable memoized props bailout when context might have changed
Dan Abramov committed
Nov 14, 2016 at 18:24 UTC
eedca6f641d2ea52fb1de5f12f61bc21b7c5f0d6
4 files changed
+19
-10
scripts/fiber/tests-failing.txt
-2
@@ -425,8 +425,6 @@ src/renderers/shared/stack/reconciler/__tests__/ReactCompositeComponent-test.js
425
* should warn about `setState` on unmounted components
426
* should warn about `setState` in render
427
* should warn about `setState` in getChildContext
428
-* should pass context when re-rendered for static child
429
-* should pass context when re-rendered for static child within a composite component
428
* unmasked context propagates through updates
429
* should trigger componentWillReceiveProps for context changes
430
* should update refs if shouldComponentUpdate gives false
scripts/fiber/tests-passing.txt
+2
@@ -1035,6 +1035,8 @@ src/renderers/shared/stack/reconciler/__tests__/ReactCompositeComponent-test.js
1035
* should warn when componentDidUnmount method is defined
1036
* should pass context to children when not owner
1037
* should skip update when rerendering element in container
1038
+* should pass context when re-rendered for static child
1039
+* should pass context when re-rendered for static child within a composite component
1040
* should pass context transitively
1041
* should pass context when re-rendered
1042
* only renders once if updated in componentWillReceiveProps
src/renderers/shared/fiber/ReactFiberBeginWork.js
+5
-3
@@ -28,6 +28,7 @@ var ReactTypeOfWork = require('ReactTypeOfWork');
28
var {
29
getMaskedContext,
30
isContextProvider,
31
+ hasContextChanged,
32
pushContextProvider,
33
resetContext,
34
} = require('ReactFiberContext');
@@ -200,7 +201,7 @@ module.exports = function<T, P, I, TI, C>(
201
reconcileChildren(current, workInProgress, nextChildren);
202
// Put context on the stack because we will work on children
203
if (isContextProvider(workInProgress)) {
203
- pushContextProvider(workInProgress);
204
+ pushContextProvider(workInProgress, true);
205
}
206
return workInProgress.child;
207
}
@@ -361,7 +362,7 @@ module.exports = function<T, P, I, TI, C>(
362
markChildAsProgressed(current, workInProgress, priorityLevel);
363
// Put context on the stack because we will work on children
364
if (isContextProvider(workInProgress)) {
364
- pushContextProvider(workInProgress);
365
+ pushContextProvider(workInProgress, false);
366
}
367
return workInProgress.child;
368
}
@@ -398,7 +399,8 @@ module.exports = function<T, P, I, TI, C>(
399
workInProgress.memoizedProps !== null &&
400
workInProgress.pendingProps === workInProgress.memoizedProps
401
)) &&
401
- workInProgress.updateQueue === null) {
402
+ workInProgress.updateQueue === null &&
403
+ !hasContextChanged()) {
404
return bailoutOnAlreadyFinishedWork(current, workInProgress);
405
}
406
src/renderers/shared/fiber/ReactFiberContext.js
+12
-5
@@ -28,13 +28,14 @@ if (__DEV__) {
28
}
29
30
let index = -1;
31
-const stack = [];
31
+const contextStack : Array<Object> = [];
32
+const didPerformWorkStack : Array<boolean> = [];
33
34
function getUnmaskedContext() {
35
if (index === -1) {
36
return emptyObject;
37
}
37
- return stack[index];
38
+ return contextStack[index];
39
}
40
41
exports.getMaskedContext = function(fiber : Fiber) {
@@ -59,6 +60,10 @@ exports.getMaskedContext = function(fiber : Fiber) {
60
return context;
61
};
62
63
+exports.hasContextChanged = function() : boolean {
64
+ return index > -1 && didPerformWorkStack[index];
65
+};
66
+
67
exports.isContextProvider = function(fiber : Fiber) : boolean {
68
return (
69
fiber.tag === ClassComponent &&
@@ -67,11 +72,12 @@ exports.isContextProvider = function(fiber : Fiber) : boolean {
72
};
73
74
exports.popContextProvider = function() : void {
70
- stack[index] = emptyObject;
75
+ contextStack[index] = emptyObject;
76
+ didPerformWorkStack[index] = false;
77
index--;
78
};
79
74
-exports.pushContextProvider = function(fiber : Fiber) : void {
80
+exports.pushContextProvider = function(fiber : Fiber, didPerformWork : boolean) : void {
81
const instance = fiber.stateNode;
82
const childContextTypes = fiber.type.childContextTypes;
83
const childContext = instance.getChildContext();
@@ -92,7 +98,8 @@ exports.pushContextProvider = function(fiber : Fiber) : void {
98
99
const mergedContext = Object.assign({}, getUnmaskedContext(), childContext);
100
index++;
95
- stack[index] = mergedContext;
101
+ contextStack[index] = mergedContext;
102
+ didPerformWorkStack[index] = didPerformWork;
103
};
104
105
exports.resetContext = function() : void {