Derive, don't sync
Compute values from props and state during render, not in an effect.
React docsreact.dev
References: You Might Not Need an Effect
From vercel-react-best-practices, rule rerender-derived-state-no-effect.
Full name: two renders or one
Type in either field; red bars are stale frames.
useState + useEffectBad
fullNamestatefirst + ' ' + last
0 renders0 stale frames
useEffect(() => setFullName(…), [first, last])Derived in renderGood
fullNameconstfirst + ' ' + last
0 renders0 stale frames
const fullName = first + ' ' + lastconst fullName = firstName + ' ' + lastName
Reset with a key, not effect
Switch recipient, then type right away.
Reset in an effectBad
fresh
0 renders last switch0 stale frames
useEffect(() => setDraft(''), [userId])Reset with keyGood
0 renders last switch1 mounts
<NoteEditor key={userId} userId={userId} /><NoteEditor key={userId} userId={userId} />
A copy drifts from its source
Add or remove people, then type in the filter.
Copied into stateBad
0 rendersmatches source
useEffect(() => setVisible(items.filter(match)), [query])Derived in renderGood
0 rendersmatches source
const visible = items.filter(match)const visible = useMemo(() => items.filter(match), [items, query])
Why it matters, pros and cons
Why it matters
An effect's setState costs a second render and a stale frame, and can drift.
Pros
- One render per change, no stale frame.
- One source of truth.
- No effect or dependency array to break.
Cons
- Expensive derivations need
useMemo, not state. keydiscards the whole subtree's DOM and state.- A draft seeded once from a prop is real state.