When should you NOT use useEffect
Don't use useEffect for: deriving state (compute during render); transforming data for rendering (compute or useMemo); responding to user events (do it in the handler); resetting state on prop change (use a `key`); chaining state updates (combine into one). Effects are for *synchronizing with external systems* — DOM, subscriptions, APIs — not for in-app data flow.
useEffect is for synchronizing with external systems (DOM, subscriptions, network). Most "useEffect bugs" are actually misuses: code that should be in the render path, in a handler, or in a key — but ended up in an effect.
Misuse #1 — Deriving state from props
// BAD
const [fullName, setFullName] = useState("");
useEffect(() => {
setFullName(`${firstName} ${lastName}`);
}, [firstName, lastName]);This is double-rendering noise. Compute during render:
// GOOD
const fullName = `${firstName} ${lastName}`;Or memoize if expensive:
const fullName = useMemo(() => expensive(firstName, lastName), [firstName, lastName]);Misuse #2 — Filtering / transforming a list
// BAD
const [visible, setVisible] = useState([]);
useEffect(() => {
setVisible(items.filter(matches(query)));
}, [items, query]);Same problem. Compute during render or with useMemo:
const visible = useMemo(() => items.filter(matches(query)), [items, query]);Misuse #3 — Responding to a user event
// BAD
useEffect(() => {
if (justSubmitted) {
api.send(formData);
setJustSubmitted(false);
}
}, [justSubmitted]);Put the side effect in the event handler:
const onSubmit = () => api.send(formData);Misuse #4 — Resetting state on prop change
// BAD
useEffect(() => {
setSelected(null);
}, [userId]);Use the key prop to remount and reset:
<UserPanel key={userId} userId={userId} />Inside UserPanel, useState(null) re-initializes on key change. No effect needed.
Misuse #5 — Chaining state updates
// BAD
useEffect(() => { setB(deriveB(a)); }, [a]);
useEffect(() => { setC(deriveC(b)); }, [b]);Each chain step is a render. Combine into one derivation:
const b = deriveB(a);
const c = deriveC(b);If b/c aren't state (just derived), they don't need to be.
Misuse #6 — Initializing state from props
// BAD
const [value, setValue] = useState(0);
useEffect(() => { setValue(initial); }, []);Just pass it to useState:
const [value, setValue] = useState(initial);If you want the value to reset on prop change, use key (misuse #4).
Misuse #7 — Notifying the parent of a change
// BAD
useEffect(() => { onChange(value); }, [value]);Call onChange directly when you update:
const handle = (v) => { setValue(v); onChange(v); };Misuse #8 — Setting state during render (accidentally via effect)
// BAD
useEffect(() => { if (a > 100) setB(true); }, [a]);If b is derived from a, just compute it:
const b = a > 100;Misuse #9 — useEffect with a setTimeout/setInterval for animation
// BAD — frames lost, no rAF integration
useEffect(() => {
const t = setInterval(() => setX(x + 1), 16);
return () => clearInterval(t);
}, [x]);Use requestAnimationFrame and refs (see [[build-a-cursor-tracker]]).
Legitimate uses
Effects ARE for:
- Subscribing to non-React stores (Redux v8
useSyncExternalStoreis the modern path). - Connecting to / disconnecting from sockets, timers, observers.
- Reading/writing DOM that React doesn't manage (third-party libraries).
- Fetching data — though React Query / Suspense are better for most cases.
- Sending analytics / logging on view.
Mental rule
If the code reads or writes something outside React's tree, it might belong in an effect. If it transforms props into a value that the same component renders, it belongs in render.
Interview framing
"useEffect is for synchronizing with external systems — DOM, subscriptions, sockets, timers, third-party libraries. The common misuses: deriving state from props (compute during render or useMemo); filtering/transforming for render (same); responding to user events (do it in the handler); resetting state on prop change (use key to remount); chaining state updates (combine); initializing state from props (just pass to useState); notifying parents (call onChange directly). The rule: if you're transforming render-time data, it goes in render; if you're touching the outside world, it goes in an effect. Most 'useEffect bug' reports are actually 'this shouldn't be an effect at all'."
Follow-up questions
- •How do you reset state when a prop changes?
- •When is useMemo the right alternative to useEffect?
- •What does 'key' actually do here?
- •When IS useEffect the right tool?
Common mistakes
- •Deriving state in an effect → double-render.
- •Effects to call event-like side effects.
- •Effects to reset state instead of using key.
- •Chains of effects feeding each other.
Performance considerations
- •Removing useless effects removes double-renders. Memoize derivations only when measured to be expensive.
Edge cases
- •External libraries that demand an imperative effect dance — fine.
- •Effects in custom hooks that wrap third-party state — fine.
- •Suspense-based data fetching makes data-loading effects unnecessary.
Real-world examples
- •React docs 'You Might Not Need an Effect' page is canonical.
- •Dan Abramov's 'A Complete Guide to useEffect' on misuses.