On this page
The core idea
An effect runs after React has updated the screen. Its purpose is synchronisation with an external system: a network request, a subscription, a timer, a browser API or a non-React widget. If a value can be calculated from props or state, calculate it during rendering instead. If something should happen because the user clicked a button, put that logic in the event handler. Many effect bugs, including loops and stale values, disappear once effects are reserved for the external systems they were designed for.
A practical approach
Step 1
For each effect, finish the sentence 'this effect keeps the component synchronised with ...'. If you cannot name an external system, the effect is probably unnecessary.
Step 2
Move calculations into rendering, and wrap them in useMemo only if profiling shows they are expensive.
Step 3
Move user-triggered work, such as submitting a form or showing a toast, into the event handler that caused it.
Step 4
For real effects, return a cleanup function that unsubscribes, clears timers or ignores responses that arrive after the component changed.
Step 5
List every value the effect reads in its dependency array, and let the linter rule for hooks enforce it.
Worked example
A profile page stores fullName in state and updates it in an effect whenever firstName or lastName changes. Each keystroke renders twice, and on slow devices the field briefly shows the old name. Replacing the effect with const fullName = `${firstName} ${lastName}` removes the extra render and the flicker. The page keeps one genuine effect: subscribing to the learner's notification channel, with cleanup on unmount.
A mistake to avoid
Do not silence the dependency linter to stop an effect from running repeatedly. A missing dependency usually means the effect reads stale values; the right fix is to restructure the effect or move logic out of it.
Try it yourself
Search a React project for useEffect. For each one, write down the external system it synchronises with. Remove or rewrite at least one effect that only derives data or reacts to an event.
Your implementation checklist
- Every effect synchronises with a named external system
- Derived values are calculated during rendering
- Event-driven logic lives in event handlers
- Effects clean up subscriptions, timers and stale requests
- Dependency arrays are complete without linter overrides
Share or cite this guide
Innovate with Ajay Editorial (2026-10-07). Use React Effects for Synchronisation, Not for Derived Data. https://innovatewithajay.com/blogs/use-react-effects-for-synchronisation
