gotchareactMajor
React useEffect cleanup not running on fast remount in StrictMode
Viewed 0 times
React 18+
useEffectdouble mountStrictModecleanupAbortControllerrace condition
browsernodejs
Error Messages
Problem
In React 18+ development mode, useEffect runs twice on mount due to StrictMode. This causes double API calls, duplicate subscriptions, or race conditions.
Solution
This is intentional React 18 behavior. Your effect MUST handle cleanup properly. For fetch: use an AbortController. For subscriptions: return the unsubscribe function. For timers: clear them in cleanup. This only happens in dev mode with StrictMode; production runs effects once.
Why
React 18 StrictMode intentionally double-invokes effects in development to ensure cleanup works correctly.
Code Snippets
Proper cleanup with AbortController
useEffect(() => {
const controller = new AbortController();
fetch("/api/data", { signal: controller.signal })
.then(res => res.json()).then(setData)
.catch(e => { if (e.name !== "AbortError") throw e; });
return () => controller.abort();
}, []);Revisions (0)
No revisions yet.