Skip to content
tezvyn:

Describe combining useContext and useReducer for scalable feature state

Source: react.devHardHow cards are made

Describe combining useContext and useReducer for scalable feature state

This tests replacing prop drilling with a context-reducer pattern. A strong answer covers two contexts for state and dispatch, a provider wrapping the subtree, and a pure reducer. A red flag is one global context or async logic inside the reducer.

What's really being asked

Whether you understand how to scale a React feature beyond local component state without creating a brittle prop-drilling hierarchy or an over-engineered global store. The interviewer wants to see that you can encapsulate state logic inside a single feature boundary, keep state updates predictable and traceable, and expose that state to deeply nested consumers through React's built-in primitives rather than external libraries.

The full answer

First, create two distinct contexts, one for the current state and one for the dispatch function, so that components calling dispatch do not re-render when state changes. Second, build a provider component that calls useReducer and supplies both values to their respective contexts, placing this provider at the root of the feature subtree. Third, keep the reducer function pure, deterministic, and colocated with the provider or in a dedicated module, handling all state transitions through explicit action types. Fourth, define clear action shapes and optionally use TypeScript or PropTypes so consumers know what payloads are expected. Fifth, consume the contexts with custom hooks that throw if used outside the provider, enforcing correct usage.

The mistakes people make

Putting the reducer and context in the same file as UI components, which destroys separation of concerns. Using a single context object that contains both state and dispatch, causing every consumer to re-render on every state change. Performing side effects like API calls inside the reducer instead of in event handlers or effects that dispatch afterward. Creating one giant global context for the entire application instead of scoping providers to specific features. Forgetting to memoize the context value object, which breaks shouldComponentUpdate or React.memo optimizations down the tree.

What usually comes next

How would you persist this state to localStorage or sync it with a server? The answer should describe an effect inside the provider or a middleware pattern, not async reducers. How do you prevent excessive re-renders when the state object grows large? The answer should mention splitting contexts, memoizing derived state, or using selectors. Would you reach for Redux or Zustand instead? A strong response compares trade-offs, noting that context plus reducer is excellent for localized medium-frequency updates but can struggle with very high-frequency updates compared to specialized libraries.

A concrete example

Imagine a complex Kanban board feature. You would define a BoardProvider that wraps a single project view. Inside BoardProvider, useReducer manages columns, cards, and drag-drop state. Two contexts, BoardStateContext and BoardDispatchContext, are created. A useBoardState hook reads columns and cards, while a useBoardDispatch hook returns the dispatch function. Card components call dispatch with type MOVE_CARD and payload sourceId and targetColumnId. The reducer computes the new column order immutably. No props pass through Column or Card components, and the entire state layer can be deleted or tested independently of the UI.

Interview question

In a context-reducer feature, a component only dispatches actions but never reads state. How do you prevent it from re-rendering when state changes?

  • a.Wrap the component in React.memo to bail out of unnecessary renders
  • b.Move the dispatch function into a useCallback with an empty dependency array
  • c.Provide state and dispatch through two separate contexts and consume only the dispatch contextCorrect
  • d.Store the state in a ref so that context consumers do not detect value changes
Why?

Splitting state and dispatch into two contexts lets components subscribe only to the stable dispatch function, isolating them from state reference changes. React.memo cannot prevent re-renders caused by a changing context value, and useReducer already returns a stable dispatch, so memoizing it with useCallback does not solve the subscription problem.

Just read this? Test yourself on what you have been reading.

Read the original → react.dev

You just looked this up. Could you explain it out loud?

That is the part interviews actually test. Tezvyn takes questions like this one and gives you what the interviewer is really checking, the answer that lands, and the mistake that ends the conversation, in the four minutes before your next meeting.

The iPhone app is on the way

We are building it. Until it lands, nothing here is held back from you: every interview card, your saved cards, streaks and the job board all work in Safari, plus hundreds of free practice quizzes of thirty questions each. Sign in and it all carries over to the app the day it arrives.

Want it as an icon? Tap Share at the bottom of Safari, then Add to Home Screen. It opens full screen and the cards you have read stay available offline.

Get it on Google PlayiPhone app coming soon

We are hiring for this. Open roles that interview on react — each one lists the topics its interview covers.

See open roles