Run Code After Render — For Side Effects
useEffect
`useEffect` runs a function after React commits a render. Use it for side effects — fetching, subscriptions, DOM access.
What you'll learn
- Run code after every render
- Pick the right dependency array
- Recognize what is and isn't a side effect
The render body should be pure — given the same inputs, return
the same JSX, no side effects. But real apps need side effects:
fetching data, subscribing to a websocket, syncing the document
title. That’s what useEffect is for.
The Shape
import { useEffect } from "react";
function Page({ title }) {
useEffect(() => {
document.title = title;
}, [title]);
return <h1>{title}</h1>;
} useEffect(fn, deps):
fn— the effect to run, AFTER React commits the renderdeps— values it depends on; effect re-runs only when any of them change
When Effects Run
deps you pass | When the effect runs |
|---|---|
[a, b] | After mount, and whenever a or b changes |
[] | Once, after mount only |
| omitted | After EVERY render — almost never what you want |
A Typical Use: Fetching
function UserCard({ id }) {
const [user, setUser] = useState(null);
useEffect(() => {
fetch(`/api/users/${id}`)
.then(r => r.json())
.then(setUser);
}, [id]);
if (!user) return <p>Loading…</p>;
return <p>{user.name}</p>;
} This re-fetches whenever id changes. (You’ll learn how to handle
race conditions and aborts a few lessons from now.)
Don’t Set State Unconditionally Inside
This is an infinite loop:
// ✗
useEffect(() => {
setCount(count + 1); // updates state → re-render → effect → ...
}); Either pass a dep array that prevents it ([] for once-only) or
update state based on a real trigger, not “every render”.
What Belongs In An Effect
| Belongs | Does NOT belong |
|---|---|
fetch, network requests | Anything you can compute from state/props |
addEventListener on window/document | Code that runs on a user event — that’s a handler |
| Subscribing to a store, websocket, timer | Local computation |
| Syncing the page title, scroll, focus | Calling another component’s setter “to sync state” |
If you’re tempted to use an effect to copy one piece of state into another, you almost certainly want to derive it instead. The “effects vs events” lesson covers this in more detail.
StrictMode Runs Effects Twice in Dev
In development with <StrictMode>, effects fire twice on mount.
This is intentional — it surfaces effects that forgot a cleanup.
It does NOT happen in production builds.
If your effect breaks when fired twice, it’s a bug — usually a missing cleanup. Fix the effect; don’t disable StrictMode.
Up Next
The dependency array is the single most important and
misunderstood part of useEffect. Time to dig in.