useEffect vs Event Handlers
Event handlers respond directly to specific user interactions, while effects run after React commits a render and are used to synchronize the component with external systems. Choosing between them depends on whether the work is caused by an interaction or by the component being rendered with particular state or props.
An event handler runs because a particular interaction occurred, such as a click, form submission, or key press. It is the natural place for interaction-specific work, such as submitting data, updating state in response to a click, or starting an action the user explicitly requested.
An effect declared with `useEffect` runs after React commits a render when its dependencies indicate that the synchronization should be performed. Effects are primarily for connecting React state to something outside React, such as a browser API, subscription, timer, network connection, or third-party widget.
A useful question is: "What caused this code to run?" If the answer is "the user clicked this button," an event handler is usually appropriate. If the answer is "the component is now rendered with these props or state values, and an external system must be synchronized," an effect may be appropriate.
Effects should not be used merely to transform data for rendering or to handle ordinary user interactions. For example, deriving a filtered list from props during render is usually simpler than storing it in state and updating it from an effect.
An effect can return a cleanup function. React uses cleanup when an effect is replaced or the component is removed, which is useful for unsubscribing, clearing timers, disconnecting resources, or undoing an external synchronization.
Key points
- Event handlers are triggered by specific interactions.
- Effects run after committed renders and synchronize with external systems.
- Put interaction-specific logic in the relevant event handler.
- Do not use an effect just to derive values that can be calculated during render.
- Use effect cleanup to release subscriptions, timers, or other external resources.
Interview questions
When should you use an event handler instead of `useEffect`?
Use an event handler when the code should run because of a specific interaction, such as a click or form submission. Put the interaction-specific operation directly in that handler. Use `useEffect` when a committed render means an external system needs to be synchronized. This distinction prevents effects from becoming a general-purpose place for application logic.
Why can using `useEffect` to derive state be unnecessary?
If a value can be calculated from existing props or state during rendering, storing it separately creates another state value that can become inconsistent. An effect would also require an additional render after the derived state is updated. Computing the value directly keeps the data flow simpler. Effects should generally be reserved for synchronization with external systems.
What happens when an effect's dependencies change?
After React commits a render in which a dependency has changed, React runs the effect according to the hook's dependency list. If the previous effect returned cleanup, React performs that cleanup before running the replacement effect. This lets an effect stop synchronizing with the old values before synchronizing with the new ones. The dependency list therefore describes the reactive values that the effect uses for synchronization.
How would you decide whether a piece of logic belongs in an effect?
First identify what triggers the logic. If a specific user action is the trigger, I would normally put the logic in that event handler. If the trigger is that the component has committed with particular reactive values and an external system must match them, I would consider an effect. I would also check whether the operation can be performed during render as a pure calculation, because that should not require an effect.