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 71fb3e2 commit 617e7d3
Show file tree
Hide file tree
Showing 6 changed files with 41 additions and 11 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 @@ -97,8 +97,6 @@ src/renderers/shared/hooks/__tests__/ReactHostOperationHistoryHook-test.js
* gets reported when a child is removed

src/renderers/shared/shared/__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 @@ -1402,6 +1402,8 @@ src/renderers/shared/shared/__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
2 changes: 1 addition & 1 deletion src/renderers/shared/fiber/ReactFiberBeginWork.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ if (__DEV__) {
module.exports = function<T, P, I, TI, PI, C, CX, PL>(
config : HostConfig<T, P, I, TI, PI, C, CX, PL>,
hostContext : HostContext<C, CX>,
scheduleUpdate : (fiber : Fiber, priorityLevel : PriorityLevel) => void,
scheduleUpdate : (fiber : Fiber, priorityLevel : PriorityLevel, callerName : string | null) => void,
getPriorityContext : () => PriorityLevel,
) {

Expand Down
20 changes: 16 additions & 4 deletions src/renderers/shared/fiber/ReactFiberClassComponent.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ var invariant = require('invariant');
const isArray = Array.isArray;

module.exports = function(
scheduleUpdate : (fiber : Fiber, priorityLevel : PriorityLevel) => void,
scheduleUpdate : (fiber : Fiber, priorityLevel : PriorityLevel, callerName : string | null) => void,
getPriorityContext : () => PriorityLevel,
memoizeProps: (workInProgress : Fiber, props : any) => void,
memoizeState: (workInProgress : Fiber, state : any) => void,
Expand All @@ -54,19 +54,31 @@ module.exports = function(
const fiber = ReactInstanceMap.get(instance);
const priorityLevel = getPriorityContext();
addUpdate(fiber, partialState, callback || null, priorityLevel);
scheduleUpdate(fiber, priorityLevel);
if (__DEV__) {
scheduleUpdate(fiber, priorityLevel, 'setState');
} else {
scheduleUpdate(fiber, priorityLevel, null);
}
},
enqueueReplaceState(instance, state, callback) {
const fiber = ReactInstanceMap.get(instance);
const priorityLevel = getPriorityContext();
addReplaceUpdate(fiber, state, callback || null, priorityLevel);
scheduleUpdate(fiber, priorityLevel);
if (__DEV__) {
scheduleUpdate(fiber, priorityLevel, 'replaceState');
} else {
scheduleUpdate(fiber, priorityLevel, null);
}
},
enqueueForceUpdate(instance, callback) {
const fiber = ReactInstanceMap.get(instance);
const priorityLevel = getPriorityContext();
addForceUpdate(fiber, callback || null, priorityLevel);
scheduleUpdate(fiber, priorityLevel);
if (__DEV__) {
scheduleUpdate(fiber, priorityLevel, 'forceUpdate');
} else {
scheduleUpdate(fiber, priorityLevel, null);
}
},
};

Expand Down
2 changes: 1 addition & 1 deletion src/renderers/shared/fiber/ReactFiberReconciler.js
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
const priorityLevel = getPriorityContext();
const nextState = { element };
addTopLevelUpdate(current, nextState, callback || null, priorityLevel);
scheduleUpdate(current, priorityLevel);
scheduleUpdate(current, priorityLevel, null);
}

return {
Expand Down
24 changes: 21 additions & 3 deletions src/renderers/shared/fiber/ReactFiberScheduler.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,22 @@ 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>, callerName : string) {
const ctor = instance.constructor;
warning(
false,
'%s(...): Can only update a mounted or mounting component. ' +
'This usually means you called %s() on an unmounted component. ' +
'This is a no-op.\n\nPlease check the code for the %s component.',
callerName,
callerName,
ctor && (ctor.displayName || ctor.name) || 'ReactClass'
);
};
}

var timeHeuristicForUnitOfWork = 1;
Expand Down Expand Up @@ -1084,7 +1098,7 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(config : HostConfig<T, P,
}
}

function scheduleUpdate(fiber : Fiber, priorityLevel : PriorityLevel) {
function scheduleUpdate(fiber : Fiber, priorityLevel : PriorityLevel, callerName : string | null) {
if (priorityLevel <= nextPriorityLevel) {
// We must reset the current unit of work pointer so that we restart the
// search from the root during the next tick, in case there is now higher
Expand Down Expand Up @@ -1137,7 +1151,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 (callerName && fiber.tag === ClassComponent) {
warnAboutUpdateOnUnmounted(fiber.stateNode, callerName);
}
}
return;
}
}
Expand All @@ -1155,7 +1173,7 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(config : HostConfig<T, P,
}

function scheduleErrorRecovery(fiber : Fiber) {
scheduleUpdate(fiber, TaskPriority);
scheduleUpdate(fiber, TaskPriority, null);
}

function performWithPriority(priorityLevel : PriorityLevel, fn : Function) {
Expand Down

0 comments on commit 617e7d3

Please sign in to comment.