What belongs in a useEffect, what belongs in an event handler, and what belongs in neither?
Give it 60 seconds. Say your answer out loud before you open it.
Reveal the answerHide the answer
The senior filter, in one line: effects synchronize your component with an external system. Everything else has a better home.
- Event handler: logic caused by a user action: POST on submit, navigate on click, show a toast, track an analytics event. If you can name the interaction that triggers it, it's a handler.
- Render: data derived from props or state: filtered lists, formatted names, totals. Compute it inline (memoize only if expensive).
- Effect: synchronization with something outside React: a subscription, a WebSocket, a browser API, a non-React widget, document title.
More
The common smells all appear on the React docs page "You Might Not Need an Effect". The same test catches the other smells. An effect that calls setState to transform data should become a value derived during render. An effect chain, where one effect's setState triggers the next, should become one computation in one place. Each unnecessary effect adds an extra render pass, a dependency array, and a place for stale bugs.
const [submitted, setSubmitted] = useState(false);useEffect(() => { if (submitted) postAnalytics("form_submitted"); // runs a render later, re-runs on remount}, [submitted]);const handleSubmit = () => { postAnalytics("form_submitted"); setSubmitted(true);};- Avoid
- Reacting to state to do what the handler already knew.
- Prefer
- The handler is the event.
Follow-ups an interviewer asks
Is fetching data an effect?
It's synchronization, so yes in raw React, but in application code a query library owns it; see Q7.17.
Why is the effect version of analytics worse than the handler?
It fires on remounts and StrictMode re-runs, not just the actual user action. It answers "state became X," not "user did X."



