What useEffect
does
- Runs after render.
- Can return a cleanup function.
- React guarantees: cleanup runs before the effect runs again, and on unmount.
Example
useEffect(() => { console.log("Effect starts"); return () => { console.log("Cleanup runs"); }; }, [dep]);
Key behaviors
-
Dependencies
- Empty
[]
→ run only on mount/unmount. -
[dep]
→ run wheneverdep
changes. - No array → run after every render.
- Empty
-
Cleanup
- Removes timers, aborts fetches, unsubscribes listeners.
- Runs before the next effect, preventing leaks.
-
Async effects
- You can’t mark the effect function itself
async
. - Instead, define and call an inner async function.
- Handle race conditions with cancel flags or
AbortController
.
- You can’t mark the effect function itself
Timeline mental model
Render #1 └─ Effect #1 runs Render #2 (dep changed) ├─ Cleanup from Effect #1 runs └─ Effect #2 runs Component unmount └─ Cleanup from last effect runs
Timeline diagram of how useEffect() works when user types search terms:
Component mounts with searchTerm = "c" ──────────────────────────────────────────────────────────── Render #1 useEffect #1 runs cancelled₁ = false start async #1 → fetch /api?q=c cleanup for previous effect? (none on mount) (time passes… user types) searchTerm changes to "ca" ──────────────────────────────────────────────────────────── Render #2 BEFORE running the new effect, React runs cleanup for the previous one: cleanup of useEffect #1 → set cancelled₁ = true (invalidate old effect) Now run the new effect body: useEffect #2 runs cancelled₂ = false start async #2 → fetch /api?q=ca (time passes… network completes out of order) Async #1 (for "c") finishes LATE async #1 reads cancelled₁ === true → DO NOTHING (skip setResults) Async #2 (for "ca") finishes async #2 reads cancelled₂ === false → setResults(data for "ca") ✅ correct ──────────────────────────────────────────────────────────── Outcome: Only the latest effect (for "ca") is allowed to update state. Older effects see their own 'cancelled' flag and gracefully bail out.
Top comments (0)