"Can't perform a React state update on an unmounted component" is React telling you an async operation (a fetch, a timer, a subscription) outlived the component that started it, and tried to update state after that component was already removed from the tree — a no-op that does nothing visually, but signals a real resource leak worth fixing.
This warning means a state-setting function (from useState or a class component's setState) was called after the component that owns that state had already unmounted — React ignores the update itself since there's no component left to re-render, but the warning surfaces because the underlying async operation that triggered it is still running unnecessarily.
Why This Warning Happens
Components frequently kick off async operations during their lifetime — data fetching, timers, WebSocket subscriptions — and update state when those operations resolve. If the component unmounts (navigated away from, conditionally removed, or its parent re-rendered without it) before the async operation completes, the eventual setState call fires against a component instance that no longer exists — React can't apply the update, and warns because this pattern often also indicates an uncanceled operation still consuming resources (memory, an open connection, a pending timer) needlessly.
Reproducing the Warning
A fetch that resolves after the component has unmounted:
function UserProfile({ userId }: { userId: string }) {
const [user, setUser] = useState(null);
useEffect(() => {
fetchUser(userId).then((data) => {
setUser(data); // if component unmounted before this resolves, warning fires
});
}, [userId]);
return user ? <div>{user.name}</div> : <div>Loading...</div>;
}
Navigating away from a page showing UserProfile before fetchUser resolves triggers the warning the moment the fetch does eventually complete.
Core Concepts Behind This Warning
The warning is really about an uncanceled side effect, not the harmless no-op state update itself — React silently ignoring a state update on an unmounted component isn't the problem; the problem is that whatever async operation is still running (holding a network connection, a timer, a subscription) is wasted work that should have been cleaned up when the component unmounted.
useEffect's cleanup function (the function returned from the effect) is the mechanism for canceling in-flight work when a component unmounts — any effect starting an async operation that later calls setState should have a corresponding cleanup that either cancels the operation directly (aborting a fetch) or sets a flag the async callback checks before updating state.
AbortController is the standard mechanism for actually canceling a fetch() request, distinct from just ignoring its result — canceling the underlying request (rather than just discarding its eventual result) is the more complete fix, since it also stops unnecessary network activity, not just the state update.
This pattern is especially common in React Strict Mode's double-invocation behavior in development, which mounts, unmounts, and remounts components deliberately to surface exactly this class of bug — seeing the warning specifically under Strict Mode in development, even if it "doesn't happen in production," is a legitimate signal to fix, not noise to ignore.
Fixing "Cannot Update State on an Unmounted Component"
Fix 1: Use AbortController to cancel the actual fetch on unmount, which both prevents the state update and stops the unnecessary network request:
useEffect(() => {
const controller = new AbortController();
fetchUser(userId, { signal: controller.signal })
.then((data) => setUser(data))
.catch((err) => {
if (err.name !== "AbortError") throw err;
});
return () => controller.abort();
}, [userId]);
Fix 2: Use a boolean flag checked before updating state, for async operations that can't be directly canceled (a third-party API without abort support):
useEffect(() => {
let cancelled = false;
fetchUser(userId).then((data) => {
if (!cancelled) setUser(data);
});
return () => {
cancelled = true;
};
}, [userId]);
Fix 3: For subscriptions and timers, always pair the setup with a corresponding cleanup in the same effect:
useEffect(() => {
const subscription = dataSource.subscribe((data) => setUser(data));
return () => subscription.unsubscribe();
}, [userId]);
Is Suppressing This Warning Ever an Acceptable Fix?
No — unlike some React warnings that occasionally have a legitimate suppression case, this one doesn't, because the warning itself isn't the problem; the wasted, uncanceled async work underneath it is. Suppressing the warning (or ignoring it) leaves that resource leak in place; the fix always needs to address the actual cleanup, not the message.
Preventing This Warning in Production
Pair every effect that starts an async operation with cleanup logic that cancels or ignores the result if the component unmounts before it completes — AbortController for fetch, unsubscribe functions for subscriptions, clearTimeout/clearInterval for timers. Test with React Strict Mode enabled in development specifically because its double-invocation behavior surfaces this exact class of bug reliably, well before it reaches production.
If you hit this warning, trace to the specific async operation and add proper cancellation via the effect's cleanup function — the warning disappearing is a side effect of actually fixing the leak, not a goal to chase directly.