← Debugging Guides

阅读中文版本

React Warning — State Update on an Unmounted Component

Fix "Can't perform a React state update on an unmounted component" by aborting in-flight work and cleaning up subscriptions on unmount.

intermediatedebuggingreacteffectcleanup

Symptoms

  • React warns about a state update on an unmounted component, indicating a memory leak
  • The warning appears after fast navigation away from a page
  • A fetch or timer resolves after the component is gone

Possible causes

  • An async callback calls setState after unmount
  • A subscription or interval is never cleaned up in the effect teardown
  • A promise chain has no cancellation when the effect re-runs

Diagnosis steps

Locate the async setState

grep -rn "then(.*set[A-Z]\|await .*set[A-Z]" src/

Interpretation

Any setState reachable from an async completion without a mounted guard is a candidate.

Add an abort and cleanup

git diff src/hooks/useData.js

Interpretation

An AbortController plus a cleanup return aborts the request and blocks the late update.

Root cause

React components can be unmounted at any time, but async work continues unless cancelled. When its callback fires after unmount, the setState targets a component that no longer exists, leaking memory and warning.

Fix

Cancel async work in the effect cleanup (AbortController for fetch, clearInterval for timers, unsubscribe for subscriptions) so no update can occur after unmount.

Risk note

A mounted flag in state is itself a state update; prefer external cancellation over tracking mounted.

Verify the fix

Navigate away mid-request and confirm no warning; assert the AbortController signal aborted the fetch in logs.

Symptoms

The error “React Warning — State Update on an Unmounted Component” points at a specific failure mode. This guide documents the symptoms you can observe, the commands that isolate the cause, the root cause, the fix, and the checks that prove the fix works.

Observed symptoms include:

  • React warns about a state update on an unmounted component, indicating a memory leak
  • The warning appears after fast navigation away from a page
  • A fetch or timer resolves after the component is gone

Reproduce and Diagnose

Reproduce the failure in isolation before changing any code. Work through the checks below in order; each one narrows the search space.

Step 1: Locate the async setState

grep -rn "then(.*set[A-Z]\|await .*set[A-Z]" src/

Any setState reachable from an async completion without a mounted guard is a candidate.

Step 2: Add an abort and cleanup

git diff src/hooks/useData.js

An AbortController plus a cleanup return aborts the request and blocks the late update.

Likely contributors, in order of frequency:

  • An async callback calls setState after unmount
  • A subscription or interval is never cleaned up in the effect teardown
  • A promise chain has no cancellation when the effect re-runs

Root Cause

React components can be unmounted at any time, but async work continues unless cancelled. When its callback fires after unmount, the setState targets a component that no longer exists, leaking memory and warning.

The Fix

Cancel async work in the effect cleanup (AbortController for fetch, clearInterval for timers, unsubscribe for subscriptions) so no update can occur after unmount.

Watch out: A mounted flag in state is itself a state update; prefer external cancellation over tracking mounted.

useEffect(() => {
  const controller = new AbortController();
  fetch(`/api/items`, { signal: controller.signal })
    .then((r) => r.json())
    .then(setItems)
    .catch((err) => { if (err.name !== 'AbortError') console.error(err); });

  return () => controller.abort(); // cleanup on unmount or re-run
}, []);

// timers
useEffect(() => {
  const id = setInterval(tick, 1000);
  return () => clearInterval(id);
}, []);

Verify and Prevent

Navigate away mid-request and confirm no warning; assert the AbortController signal aborted the fetch in logs.

Once verified, add a regression test that reproduces the original symptom so the failure cannot silently return.

This class of failure is usually environmental rather than pure logic, so capture the exact command, the environment variables, and the working directory in your bug report. Reproduce it in the smallest possible script, then widen the scope only once the minimal case is understood. A short written checklist for this failure mode saves hours the next time it appears.