Concept · Building apps

Derived state vs effects

If you can compute it during render, don’t store it and don’t sync it with an effect.

3 minuseEffectyou might not need an effectuseMemosingle source of truth

Derived state is any value you can calculate from props or state you already have: a filtered list, a total, a full name, whether a form is valid. The rule: compute it during render; don't store it in state, and don't keep it in sync with an effect.

jsx
// ✗ Duplicated state, synced by an effect
const [visible, setVisible] = useState([])
useEffect(() => {
  setVisible(todos.filter((t) => !t.done || showDone))
}, [todos, showDone])

// ✓ Derived during render
const visible = todos.filter((t) => !t.done || showDone)

The effect version renders twice for every change: once with the stale list and once with the right one. It needs a correct dependency array, and it can drift out of sync. The derived version is always correct. If the calculation is genuinely expensive (measure first), wrap it in useMemo.

What effects are for

useEffect is for synchronizing with something outside React: a subscription, a WebSocket, a third-party widget, document.title, or a timer. A useful test is whether the code would need to run even if nothing re-rendered. If it's just turning some data into other data, it's not an effect.

You want to…Do this instead of an effect
Compute a value from props/stateCompute it in render (useMemo if expensive)
Respond to a click or submitDo it in the event handler
Reset state when a prop changesGive the component a key
Fetch dataUse a data library or framework loader (server state)
Notify a parent of a changeCall the parent's callback in the same event handler

Choosing where state lives

  • Keep a single source of truth. Store the minimal state: the selected ID, not a copy of the selected object that goes stale when the list updates.
  • Lift state up to the nearest common parent when two components need it, and move it down when only one does.
  • Don't copy props into state (useState(props.value)). The copy ignores later prop changes. Either read the prop directly or make the component fully controlled.

Fewer effects mean fewer extra renders and fewer race conditions. See rendering and reconciliation for what each render costs.

Learn it in depth