useEffect — Syncing with the Outside World
The browser tab should say 3 books to read, and keep saying the right number as books are added and finished. The tab title is not part of React's JSX; it lives outside, in document.title. Rendering must stay pure, so where does code that touches the outside world go? Into an effect.
The rule
Effects sync with outside things, after render, when dependencies change.
import { useEffect } from 'react';
function ReadingList({ books }) {
const toRead = books.filter(b => !b.read).length;
useEffect(() => {
document.title = `${toRead} books to read`;
}, [toRead]);
return <p>{toRead} to go</p>;
}Outside things. Effects are for systems React does not control: the document title, a timer, a browser API, a network connection, a third-party widget.
After render. React runs the effect after it has committed the render to the page, so the screen is already up to date when your code runs.
When dependencies change. The second argument decides how often:
| Dependency array | When the effect runs |
|---|---|
| none | after every render |
[] |
once, after the component first appears |
[toRead] |
after the first render, then whenever toRead changed |
List every prop, state or derived value the effect reads. Leaving one out makes the effect use a stale value. The hooks lint rule points out missing ones.
Loading data. Fetching when a component appears is a common effect, but real apps usually hand this to a framework or a data library that handles caching and race conditions for you. For the fundamentals, know that it is an effect because the server is an outside system.
The shortcut
Before writing an effect, ask: "Is there an outside system here?" If not, you probably do not need one.
- Computing something from props or state (a filtered list, a total)? Do it during render.
- Responding to a click or a submit? Do it in the event handler.
"Show the number of unread books"
Derived from
books. ComputetoReadduring render. No effect.
The most common misuse is copying props or state into more state with an effect, which renders twice and can drift out of sync.
Drills
Answer fast — trust the rule.
When does an effect with no dependency array run?
An effect reads userId but its dependency array is []. What goes wrong when userId changes?
Which task most needs useEffect?
When does React run an effect relative to the screen update?
Remember
- Effects sync with outside things, after render, when dependencies change.
- No outside system? Compute during render or act in a handler.
- Trap: missing dependencies, and effects that copy state into state.
