tezvyn:

Explain useReducer and when to prefer it over useState

AI-drafted, machine-checkedSource: react.devintermediate
Explain useReducer and when to prefer it over useState

Tests if you know useReducer centralizes complex state transitions better than scattered useState. Answer: define reducer/dispatch, then contrast with useState via interdependent fields or deep updates. Red flag: calling it only for global state or Redux.

WHAT THIS TESTS: The interviewer wants to see that you understand state colocation and transition logic. useState is great for independent scalar values, but once updates involve multiple related fields, conditional transitions, or derived next-state values, scattering useState calls creates bugs and stale closures. This question checks whether you can identify that inflection point and explain how a pure reducer centralizes logic outside the component body.

A GOOD ANSWER COVERS: First, define the signature: useReducer takes a reducer function, an initial argument, and an optional initializer, returning the current state and a dispatch function. Second, emphasize that the reducer must be pure and lives outside the component, which makes state transitions testable and predictable. Third, contrast with useState: multiple useState calls force you to coordinate setters inside event handlers or effects, whereas useReducer moves that coordination into a single function. Fourth, give a decision heuristic: reach for useReducer when the next state depends on the previous state in a non-trivial way, when multiple sub-values must update atomically, or when you are modeling a state machine with explicit actions.

COMMON WRONG ANSWERS: Saying useReducer is only for global state or large apps. Confusing dispatch with asynchronous behavior; dispatch is synchronous and state reads are stale until the next render. Arguing that useReducer improves performance over useState without mentioning React.memo or other optimizations, since the hook itself does not memoize child renders. Writing impure reducers that mutate state or perform side effects like API calls inside the reducer. Recreating the initial state on every render by passing an object literal directly instead of using the init function or memoizing the initial value.

LIKELY FOLLOW-UPS: How would you avoid recreating the initial state on every render? The correct pattern is to pass an init function or a stable initialArg. How do you reset state? You can pass a key prop to the component or dispatch a reset action that returns the initial state. Can you use useReducer with Context? Yes, but the interviewer may probe whether you understand that Context alone does not prevent re-renders of all consumers. When would you still prefer useState? For simple independent booleans, strings, or numbers where a reducer would add boilerplate.

ONE CONCRETE EXAMPLE: Imagine a reservation wizard with three steps: select date, select time, enter contact info. If the user changes the date, the available time slots must clear and the step indicator must reset to one. With useState you would need separate setters for date, times, step, and error, plus a handler that calls them in the right order. With useReducer you dispatch a single CHANGE_DATE action; the reducer returns the next state where date is updated, time is null, step is one, and error is cleared, all atomically and without coupling the UI to the transition rules.

Source: react.dev

Read the original → react.dev

Get five bites like this every day.

Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.