useEffect

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.

5 min read Level 2/5 #react#hooks#useEffect
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 render
  • deps — values it depends on; effect re-runs only when any of them change

When Effects Run

deps you passWhen the effect runs
[a, b]After mount, and whenever a or b changes
[]Once, after mount only
omittedAfter 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

BelongsDoes NOT belong
fetch, network requestsAnything you can compute from state/props
addEventListener on window/documentCode that runs on a user event — that’s a handler
Subscribing to a store, websocket, timerLocal computation
Syncing the page title, scroll, focusCalling 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.

Dependencies →