Skip to content

Commit

Permalink
Warn about calling setState on an unmounted component
Browse files Browse the repository at this point in the history
  • Loading branch information
acdlite committed Feb 8, 2017
1 parent 3955e22 commit e9aca8e
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 13 deletions.
2 changes: 0 additions & 2 deletions scripts/fiber/tests-passing-except-dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,6 @@ src/renderers/__tests__/ReactComponentTreeHook-test.js
* works

src/renderers/__tests__/ReactCompositeComponent-test.js
* should warn about `forceUpdate` on unmounted components
* should warn about `setState` on unmounted components
* should warn about `setState` in render
* should warn about `setState` in getChildContext
* should disallow nested render calls
Expand Down
2 changes: 2 additions & 0 deletions scripts/fiber/tests-passing.txt
Original file line number Diff line number Diff line change
Expand Up @@ -622,6 +622,8 @@ src/renderers/__tests__/ReactCompositeComponent-test.js
* should not pass this to getDefaultProps
* should use default values for undefined props
* should not mutate passed-in props object
* should warn about `forceUpdate` on unmounted components
* should warn about `setState` on unmounted components
* should silently allow `setState`, not call cb on unmounting components
* should cleanup even if render() fatals
* should call componentWillUnmount before unmounting
Expand Down
28 changes: 18 additions & 10 deletions src/renderers/__tests__/ReactCompositeComponent-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -277,11 +277,15 @@ describe('ReactCompositeComponent', () => {

instance.forceUpdate();
expectDev(console.error.calls.count()).toBe(1);
expectDev(console.error.calls.argsFor(0)[0]).toBe(
'Warning: forceUpdate(...): Can only update a mounted or ' +
'mounting component. This usually means you called forceUpdate() on an ' +
'unmounted component. This is a no-op.\n\nPlease check the code for the ' +
'Component component.'
expectDev(console.error.calls.argsFor(0)[0]).toContain(
ReactDOMFeatureFlags.useFiber ?
'Can only update a mounted or mounting component. This usually means ' +
'you called setState, replaceState, or forceUpdate on an unmounted ' +
'component. This is a no-op.\n\nPlease check the code for the ' +
'Component component.' :
'Can only update a mounted or mounting component. This usually means ' +
'you called forceUpdate() on an unmounted component. This is a no-op.' +
'\n\nPlease check the code for the Component component.'
);
});

Expand Down Expand Up @@ -321,11 +325,15 @@ describe('ReactCompositeComponent', () => {
expect(renders).toBe(2);

expectDev(console.error.calls.count()).toBe(1);
expectDev(console.error.calls.argsFor(0)[0]).toBe(
'Warning: setState(...): Can only update a mounted or ' +
'mounting component. This usually means you called setState() on an ' +
'unmounted component. This is a no-op.\n\nPlease check the code for the ' +
'Component component.'
expectDev(console.error.calls.argsFor(0)[0]).toContain(
ReactDOMFeatureFlags.useFiber ?
'Can only update a mounted or mounting component. This usually means ' +
'you called setState, replaceState, or forceUpdate on an unmounted ' +
'component. This is a no-op.\n\nPlease check the code for the ' +
'Component component.' :
'Can only update a mounted or mounting component. This usually means ' +
'you called setState() on an unmounted component. This is a no-op.' +
'\n\nPlease check the code for the Component component.'
);
});

Expand Down
19 changes: 18 additions & 1 deletion src/renderers/shared/fiber/ReactFiberScheduler.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,21 @@ var {
var invariant = require('invariant');

if (__DEV__) {
var warning = require('warning');
var ReactFiberInstrumentation = require('ReactFiberInstrumentation');
var ReactDebugCurrentFiber = require('ReactDebugCurrentFiber');

var warnAboutUpdateOnUnmounted = function(instance : ReactClass<any>) {
const ctor = instance.constructor;
warning(
false,
'Can only update a mounted or mounting component. This usually means ' +
'you called setState, replaceState, or forceUpdate on an unmounted ' +
'component. This is a no-op.\n\nPlease check the code for the ' +
'%s component.',
ctor && (ctor.displayName || ctor.name) || 'ReactClass'
);
};
}

var timeHeuristicForUnitOfWork = 1;
Expand Down Expand Up @@ -1137,7 +1150,11 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(config : HostConfig<T, P,
return;
}
} else {
// TODO: Warn about setting state on an unmounted component.
if (__DEV__) {
if (fiber.tag === ClassComponent) {
warnAboutUpdateOnUnmounted(fiber.stateNode);
}
}
return;
}
}
Expand Down

0 comments on commit e9aca8e

Please sign in to comment.