@samitouri / QOS-React / commits / 75ee3c1424

Warn about setState inside getChildContext

Stack uses a module called ReactInvalidSetStateWarningHook, but all it does is warn about setState inside getChildContext. Doesn't seem worth keeping around, so I didn't use it for Fiber, but if I'm mistaken I'll change it.

Andrew Clark committed Feb 7, 2017 at 14:19 UTC 75ee3c1424e0d44778512bf8fb1885eaa5fd1e9d
4 files changed +46 -10
scripts/fiber/tests-passing-except-dev.txt
-1
@@ -106,7 +106,6 @@ src/renderers/__tests__/ReactComponentTreeHook-test.native.js
106 * does not report top-level wrapper as a root
107
108 src/renderers/__tests__/ReactCompositeComponent-test.js
109 -* should warn about `setState` in getChildContext
109 * should disallow nested render calls
110
111 src/renderers/__tests__/ReactHostOperationHistoryHook-test.js
scripts/fiber/tests-passing.txt
+1
@@ -578,6 +578,7 @@ src/renderers/__tests__/ReactCompositeComponent-test.js
578 * should warn about `setState` on unmounted components
579 * should silently allow `setState`, not call cb on unmounting components
580 * should warn about `setState` in render
581 +* should warn about `setState` in getChildContext
582 * should cleanup even if render() fatals
583 * should call componentWillUnmount before unmounting
584 * should warn when shouldComponentUpdate() returns undefined
src/renderers/shared/fiber/ReactFiberContext.js
+24
@@ -47,6 +47,21 @@ let didPerformWorkStackCursor : StackCursor<boolean> = createCursor(false);
47 // pushed the next context provider, and now need to merge their contexts.
48 let previousContext : Object = emptyObject;
49
50 +if (__DEV__) {
51 + var _isProcessingChildContext = false;
52 + var onBeginProcessingChildContext = function() {
53 + _isProcessingChildContext = true;
54 + };
55 + exports.onBeginProcessingChildContext = onBeginProcessingChildContext;
56 + var onEndProcessingChildContext = function() {
57 + _isProcessingChildContext = false;
58 + };
59 + exports.onEndProcessingChildContext = onEndProcessingChildContext;
60 + exports.isProcessingChildContext = function() : boolean {
61 + return _isProcessingChildContext;
62 + };
63 +}
64 +
65 function getUnmaskedContext(workInProgress : Fiber) : Object {
66 const hasOwnContext = isContextProvider(workInProgress);
67 if (hasOwnContext) {
@@ -144,6 +159,10 @@ exports.pushTopLevelContextObject = function(fiber : Fiber, context : Object, di
159 };
160
161 function processChildContext(fiber : Fiber, parentContext : Object, isReconciling : boolean): Object {
162 + if (__DEV__) {
163 + onBeginProcessingChildContext();
164 + }
165 +
166 const instance = fiber.stateNode;
167 const childContextTypes = fiber.type.childContextTypes;
168
@@ -189,6 +208,11 @@ function processChildContext(fiber : Fiber, parentContext : Object, isReconcilin
208 checkReactTypeSpec(childContextTypes, childContext, 'child context', name);
209 ReactDebugCurrentFrame.current = null;
210 }
211 +
212 + if (__DEV__) {
213 + onEndProcessingChildContext();
214 + }
215 +
216 return {...parentContext, ...childContext};
217 }
218 exports.processChildContext = processChildContext;
src/renderers/shared/fiber/ReactFiberScheduler.js
+21 -9
@@ -90,6 +90,10 @@ if (__DEV__) {
90 var warning = require('warning');
91 var ReactFiberInstrumentation = require('ReactFiberInstrumentation');
92 var ReactDebugCurrentFiber = require('ReactDebugCurrentFiber');
93 + var {
94 + isProcessingChildContext,
95 + onEndProcessingChildContext,
96 + } = require('ReactFiberContext');
97
98 var warnAboutUpdateOnUnmounted = function(instance : ReactClass<any>) {
99 const ctor = instance.constructor;
@@ -103,14 +107,21 @@ if (__DEV__) {
107 );
108 };
109
106 - var warnAboutUpdateInRender = function(instance : ReactClass<any>) {
107 - warning(
108 - ReactCurrentOwner.current == null,
109 - 'Cannot update during an existing state transition (such as within ' +
110 - '`render` or another component\'s constructor). Render methods should ' +
111 - 'be a pure function of props and state; constructor side-effects are ' +
112 - 'an anti-pattern, but can be moved to `componentWillMount`.'
113 - );
110 + var warnAboutInvalidUpdates = function(instance : ReactClass<any>) {
111 + if (isProcessingChildContext()) {
112 + warning(
113 + false,
114 + 'setState(...): Cannot call setState() inside getChildContext()',
115 + );
116 + } else if (ReactCurrentOwner.current != null) {
117 + warning(
118 + false,
119 + 'Cannot update during an existing state transition (such as within ' +
120 + '`render` or another component\'s constructor). Render methods should ' +
121 + 'be a pure function of props and state; constructor side-effects are ' +
122 + 'an anti-pattern, but can be moved to `componentWillMount`.'
123 + );
124 + }
125 };
126 }
127
@@ -869,6 +880,7 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(config : HostConfig<T, P,
880 ReactCurrentOwner.current = null;
881 if (__DEV__) {
882 ReactDebugCurrentFiber.current = null;
883 + onEndProcessingChildContext();
884 }
885 // It is no longer valid because this unit of work failed.
886 nextUnitOfWork = null;
@@ -1115,7 +1127,7 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(config : HostConfig<T, P,
1127 if (__DEV__) {
1128 if (fiber.tag === ClassComponent) {
1129 const instance = fiber.stateNode;
1118 - warnAboutUpdateInRender(instance);
1130 + warnAboutInvalidUpdates(instance);
1131 }
1132 }
1133