effects
useEffect
Runs a side effect after the browser has painted the committed render. Reach for it for subscriptions, data fetching, DOM syncing with external systems, timers, and anything that must not block the visual update.
useEffect(setup, dependencies?) Parameters & Behavior
| Parameter | Purpose |
|---|---|
| setup | Function containing the effect; may return a cleanup function |
| dependencies | Array of reactive values — the effect re-runs when any changes (Object.is compared) |
| [] (empty deps) | Run once after mount (twice in Strict Mode dev) and clean up on unmount |
| no deps arg | Run after every render — almost always a bug; add a deps array |
Examples
useEffect(() => {
const id = setInterval(() => setTick(t => t + 1), 1000);
return () => clearInterval(id);
}, []); Timer with cleanup so it never leaks after unmount
useEffect(() => {
const ctrl = new AbortController();
fetch(`/api/users/${id}`, { signal: ctrl.signal })
.then(r => r.json()).then(setUser);
return () => ctrl.abort();
}, [id]); Fetch scoped by id — cancels the in-flight request if id changes
useEffect(() => {
const onResize = () => setW(window.innerWidth);
window.addEventListener('resize', onResize);
return () => window.removeEventListener('resize', onResize);
}, []); Subscribe/unsubscribe pair for a window event
useEffect(() => { document.title = `Inbox (${count})`; }, [count]); Sync the document title with reactive state
Gotcha
Missing dependencies cause stale closures — always include every reactive value the effect reads (or wrap them in useCallback/useMemo). In React 18 Strict Mode dev, effects mount → cleanup → mount again to surface missing cleanup.
Related hooks
useLayoutEffect
Runs a side effect synchronously after DOM mutations but before the browser paints. Reach for it only when you need to measure the DOM and then mutate it in a way the user must never see mid-flight (e.g. tooltip positioning).
useInsertionEffect
Runs before any DOM mutations from the current render are applied, giving CSS-in-JS libraries a chance to inject <style> tags first. Reach for it only if you are authoring a styling library — application code should not use it.
useSyncExternalStore
Subscribes a component to an external store in a way that is safe with concurrent rendering, preventing tearing. Reach for it when writing a library or reading from a store that lives outside React (Redux, Zustand, browser APIs, custom event emitters).