@samitouri / QOS-React / commits / eedca6f641

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 {