Warn about calling setState on an unmounted component
Andrew Clark committed
Feb 7, 2017 at 16:51 UTC
e9aca8e389b946c45b67dbce41e738a7bec120be
4 files changed
+38
-13
scripts/fiber/tests-passing-except-dev.txt
-2
@@ -57,8 +57,6 @@ src/renderers/__tests__/ReactComponentTreeHook-test.js
57
* works
58
59
src/renderers/__tests__/ReactCompositeComponent-test.js
60
-* should warn about `forceUpdate` on unmounted components
61
-* should warn about `setState` on unmounted components
60
* should warn about `setState` in render
61
* should warn about `setState` in getChildContext
62
* should disallow nested render calls
scripts/fiber/tests-passing.txt
+2
@@ -622,6 +622,8 @@ src/renderers/__tests__/ReactCompositeComponent-test.js
622
* should not pass this to getDefaultProps
623
* should use default values for undefined props
624
* should not mutate passed-in props object
625
+* should warn about `forceUpdate` on unmounted components
626
+* should warn about `setState` on unmounted components
627
* should silently allow `setState`, not call cb on unmounting components
628
* should cleanup even if render() fatals
629
* should call componentWillUnmount before unmounting
src/renderers/__tests__/ReactCompositeComponent-test.js
+18
-10
@@ -277,11 +277,15 @@ describe('ReactCompositeComponent', () => {
277
278
instance.forceUpdate();
279
expectDev(console.error.calls.count()).toBe(1);
280
- expectDev(console.error.calls.argsFor(0)[0]).toBe(
281
- 'Warning: forceUpdate(...): Can only update a mounted or ' +
282
- 'mounting component. This usually means you called forceUpdate() on an ' +
283
- 'unmounted component. This is a no-op.\n\nPlease check the code for the ' +
284
- 'Component component.'
280
+ expectDev(console.error.calls.argsFor(0)[0]).toContain(
281
+ ReactDOMFeatureFlags.useFiber ?
282
+ 'Can only update a mounted or mounting component. This usually means ' +
283
+ 'you called setState, replaceState, or forceUpdate on an unmounted ' +
284
+ 'component. This is a no-op.\n\nPlease check the code for the ' +
285
+ 'Component component.' :
286
+ 'Can only update a mounted or mounting component. This usually means ' +
287
+ 'you called forceUpdate() on an unmounted component. This is a no-op.' +
288
+ '\n\nPlease check the code for the Component component.'
289
);
290
});
291
@@ -321,11 +325,15 @@ describe('ReactCompositeComponent', () => {
325
expect(renders).toBe(2);
326
327
expectDev(console.error.calls.count()).toBe(1);
324
- expectDev(console.error.calls.argsFor(0)[0]).toBe(
325
- 'Warning: setState(...): Can only update a mounted or ' +
326
- 'mounting component. This usually means you called setState() on an ' +
327
- 'unmounted component. This is a no-op.\n\nPlease check the code for the ' +
328
- 'Component component.'
328
+ expectDev(console.error.calls.argsFor(0)[0]).toContain(
329
+ ReactDOMFeatureFlags.useFiber ?
330
+ 'Can only update a mounted or mounting component. This usually means ' +
331
+ 'you called setState, replaceState, or forceUpdate on an unmounted ' +
332
+ 'component. This is a no-op.\n\nPlease check the code for the ' +
333
+ 'Component component.' :
334
+ 'Can only update a mounted or mounting component. This usually means ' +
335
+ 'you called setState() on an unmounted component. This is a no-op.' +
336
+ '\n\nPlease check the code for the Component component.'
337
);
338
});
339
src/renderers/shared/fiber/ReactFiberScheduler.js
+18
-1
@@ -86,8 +86,21 @@ var {
86
var invariant = require('invariant');
87
88
if (__DEV__) {
89
+ var warning = require('warning');
90
var ReactFiberInstrumentation = require('ReactFiberInstrumentation');
91
var ReactDebugCurrentFiber = require('ReactDebugCurrentFiber');
92
+
93
+ var warnAboutUpdateOnUnmounted = function(instance : ReactClass<any>) {
94
+ const ctor = instance.constructor;
95
+ warning(
96
+ false,
97
+ 'Can only update a mounted or mounting component. This usually means ' +
98
+ 'you called setState, replaceState, or forceUpdate on an unmounted ' +
99
+ 'component. This is a no-op.\n\nPlease check the code for the ' +
100
+ '%s component.',
101
+ ctor && (ctor.displayName || ctor.name) || 'ReactClass'
102
+ );
103
+ };
104
}
105
106
var timeHeuristicForUnitOfWork = 1;
@@ -1137,7 +1150,11 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(config : HostConfig<T, P,
1150
return;
1151
}
1152
} else {
1140
- // TODO: Warn about setting state on an unmounted component.
1153
+ if (__DEV__) {
1154
+ if (fiber.tag === ClassComponent) {
1155
+ warnAboutUpdateOnUnmounted(fiber.stateNode);
1156
+ }
1157
+ }
1158
return;
1159
}
1160
}