Chapter 37: You Might Not Need an Effect
Core Idea
The single most common Effect mistake is using one where none is needed — for anything that can be computed during render, handled inside an event handler, or reset via key, an Effect adds an unnecessary extra render pass and a place for bugs to hide.
Key Concepts
- Don't use an Effect to transform data for rendering. If a value can be computed from existing props/state, compute it directly in the render body — an Effect that calls
setState from a derived value causes an extra wasted render (render → commit → Effect fires → setState → re-render) for something that could've been done in one pass.
- Don't use an Effect to handle a user event. Logic that should only run in response to a specific interaction (e.g. showing a confirmation after a purchase) belongs in the event handler that triggered it, not in an Effect watching for a state change that handler causes — Effects can't tell why a dependency changed, only that it did.
- Resetting all state when a prop changes: give the component a
key derived from that prop instead of an Effect that manually resets each state variable — changing the key remounts the component from scratch (Ch 30), which is both simpler and more complete than manually nulling out state fields.
- Adjusting some state when a prop changes (not resetting everything): compute the adjusted value directly during render rather than in an Effect — assign it to a local variable, or, if it must persist as its own state, use the "store previous props" comparison pattern during render instead of an Effect+setState round trip.
- Sharing logic between event handlers: if two different handlers need the same logic, extract a shared function they both call — don't invent a piece of state whose sole purpose is to be watched by an Effect that then runs the shared logic; that's an indirect, harder-to-trace way to call a function.
- Chains of Effects that each set state to trigger the next Effect are almost always a sign the whole chain should be one event handler with sequential logic, or a single reducer action, instead.
- When an Effect genuinely is needed: synchronizing with something outside React — subscribing to an external store, controlling a non-React widget, connecting to a server. That's the domain from Ch 36, distinct from every anti-pattern in this chapter.
Code Examples
// ❌ Unnecessary Effect: derives fullName via an extra render
useEffect(() => setFullName(firstName + ' ' + lastName), [firstName, lastName]);
// ✅ Compute during render instead
const fullName = firstName + ' ' + lastName;
- What it demonstrates: the most common form of this anti-pattern — derived-value-via-Effect — and its one-line fix.
Key Takeaways
- Before writing
useEffect, ask "am I synchronizing with something outside React, or just reacting to a change I caused myself?" — only the former needs an Effect.
- A
key change is usually a cleaner "reset everything" tool than a manually-written reset Effect.
- If removing an Effect makes a bug or a wasted render disappear, that Effect probably shouldn't have existed — this chapter is effectively a checklist for auditing existing Effects, not just writing new code.
Connects To
- Ch 36 (Synchronizing with Effects): the legitimate use case this chapter's anti-patterns are contrasted against.
- Ch 30 (Preserving and Resetting State): the
key-based reset technique used as the alternative to a reset Effect.
- Ch 31 (Extracting State Logic into a Reducer): the alternative to Effect-chains for coordinated multi-step state updates.