State and Context
How a React app decides where state lives, how it is shaped, and how it reaches the components that need it — colocation and lifting, reducers for complex transitions, context for sharing, and custom hooks for reuse. Interviewers push hard here because most React design questions ('how would you share this?', 'why does the whole tree re-render?') are really state-architecture questions.
part ofReactoverview, primer and where to startread it →on this pageshowhide
explore
- State Modeling12 questions
- Colocation and Lifting State Up4 questions
- Derived State vs Stored State4 questions
- Resetting State with Keys4 questions
- Reducers and Complex State9 questions
- useReducer Patterns and Action Design5 questions
- UI State Machines4 questions
- Context API13 questions
- Provider Patterns5 questions
- Context Re-render Pitfalls4 questions
- Context vs External Store4 questions
- Custom Hooks10 questions
- Extraction Heuristics and Hook API Design5 questions
- Common Custom-Hook Patterns5 questions
- Server State vs Client State5 questions
questions
page 2 of 2A React component calls const [state, dispatch] = useReducer(reducer, buildInitialState(items)), where buildInitialState is expensive. What happens on every re-render, and how do you fix it?
basics
~20 sbuildInitialState(items) is an ordinary argument, so JavaScript evaluates it on every render even though React only uses its result on the first one. Pass the raw value plus the function as useReducer's third argument so React calls the initializer only on mount.
In a React app, what does it mean that data fetched from an API is stale as soon as it arrives, and which events should make you revalidate it?
basics
~20 sA response describes the server at the moment it was serialized; every instant after that it is an assumption. Revalidation triggers are a design decision per data type: after your own mutation, on remount, on tab focus or reconnect, on an interval, on user request, or on a server push.
A React app's root has grown into eight nested context providers wrapping <App />. How do you tame that pyramid, and what does the nesting order actually mean?
basics
~20 sNesting order is real dependency order: a provider can only read contexts from providers above it. Tame the pyramid by moving providers down to the subtree that needs them, collecting the rest into one AppProviders component, and folding an ordered array with reduceRight where order is free.
A React context holds an object with several unrelated fields, and a component that reads only one of them re-renders whenever any field changes. Why can't the component subscribe to just that field, and what do you do about it?
basics
~20 sContext has no selector API: React compares the whole value with Object.is and notifies every reader, with no way to opt out per field. The structural fix is to split the value into several contexts along how often each part changes.
You are publishing a shared custom hook, useFilters(), that returns the current filter state plus functions to change it. Consumers memoize child components and list your functions in dependency arrays. What identity guarantees should the hook's return value make, and how do you implement them?
basics
~20 sPromise that the functions a hook returns keep the same identity for the life of the component, and that data changes identity only when it really changed. Implement stable functions with useCallback plus updater-form updates or a latest-value ref, so no state sits in their dependency list.
Implement a React `useLocalStorage(key, initialValue)` hook that returns a value and a setter which also writes to localStorage. What does a naive implementation get wrong about reading storage, parsing, and server rendering?
basics
~20 sRead storage in a lazy useState initializer, not on every render; wrap JSON.parse and every storage call in try/catch because parsing and quota both throw; support functional updates so the write matches the new state; and on the server, where localStorage does not exist, render the initial value and read storage after mount.
Write a React `useOnClickOutside(ref, handler)` hook that closes a dropdown when the user clicks elsewhere. Which document event should it listen for, and how do you stop a new inline `handler` from tearing down and re-attaching the listener on every render?
basics
~20 sAttach a document listener for pointerdown, ignore the event when ref.current contains event.target, and remove the listener in effect cleanup. Keep the handler in a ref refreshed each commit so the subscribing effect depends only on the ref, not on a handler identity that changes every render.
After lifting selection state into a page component, the value and its onChange are threaded through four intermediate React components that never use them. How do you judge whether that is a real problem, and what would you change?
basics
~20 sJudge it by how many layers ignore the props and how often the contract changes; one or two hops are fine. The first fix is composition — let the owner build the elements and pass them as children or slot props, so the middle layers never see the data. Context comes after that.
A teammate argues that filtering and sorting a 5,000-item list on every React render is wasteful and wants to keep the sorted result in useState, updated by an effect whenever the inputs change. How do you respond, and when is useMemo the right tool instead?
basics
~20 sStoring the result adds a second source of truth, a stale frame and an extra render on top of the same computation, so it is strictly worse. Measure first; if the derivation is genuinely hot, use useMemo, which caches within the render and keeps one source of truth.
A React team fixed a stale detail panel by putting key={selectedId} on their top-level page component, and now switching records also collapses the sidebar, jumps the scroll to the top and re-initialises an expensive chart. How do you decide which subtree the key actually belongs on?
basics
~20 sPut the key on the smallest component that owns exactly the state that should die with the identity change. If that state is mixed with state that must survive, extract the identity-scoped part into its own component and key that one.
A React submit flow uses a reducer whose switch is on action.type alone. A user double-clicks Submit, so a second SUBMIT arrives while the request is already in flight. How do you structure the reducer so only transitions that are legal from the current state are applied?
basics
~20 sMake the transition a function of state and action, not of action alone: switch on the current status first and handle only the actions legal there, returning the state unchanged otherwise. A transition table keyed by state then action expresses the same rule as data.
In a React useReducer, what is the difference between dispatching { type: 'setStatus', value: 'loading' } and dispatching { type: 'submitted' }, and why do reviewers push for the second style?
basics
~20 sThe first is a remote-control setter: the component decides the new state and the reducer just writes it. The second names what happened and lets the reducer decide the consequences, so the rules live in one place and each user interaction is one action.
A React UI shows a 'like' as applied immediately and sends the request in the background. What must that optimistic update keep hold of to be safe, and what has to happen when the request fails?
basics
~20 sAn optimistic update must retain the pre-update value so it can be reverted, and must treat the server's response as the truth once it arrives. On failure it reverts to that snapshot and tells the user the action did not happen — a silent revert reads as the app losing their input.
A React codebase has accumulated around thirty Context providers, and a tech lead proposes consolidating client state into a single external store. How would you evaluate that proposal, and what would you measure before committing?
basics
~20 sSeparate the contexts by role first: most are usually dependency injection of values that never change and should stay. Measure which ones actually update at runtime, how often, how many consumers need slices, and how many non-React readers exist — then migrate only those.
In a React master-detail editor, remounting the detail pane with key={recordId} correctly clears it but also throws away unsaved edits when the user clicks another record and comes back. How do you decide between identity-keyed remount and keeping per-record draft state, and what does each choice commit you to?
basics
~20 sDecide by whether losing the state is the intended product behaviour. If edits are disposable, keyed remount is the simplest correct answer. If they are work the user expects back, the draft must live above the keyed boundary, keyed by record id, and you own its lifetime.
At what point does handling server data with plain React state — useState plus effects, or a value lifted into a provider — stop being the right home, and what would you weigh before adopting a dedicated caching layer?
basics
~20 sIt stops being right once the same entity is read from several places, writes must invalidate other screens, and freshness matters — because at that point you are reimplementing keys, deduplication, revalidation and cache lifetime by hand, inconsistently, in every feature.
You own a shared React module that other teams consume — say a <FeatureFlagProvider> plus hooks. What do you decide about its public surface: what to export, whether the Provider owns its own state, and whether two instances may coexist?
basics
~20 sExport the Provider and hooks, keep the context object private, and decide deliberately whether the Provider owns state or accepts it as a prop. Then state explicitly whether two mounted instances mean two independent scopes or a misconfiguration you should detect.
A shared useDashboard() hook in your codebase takes an options object with eight boolean flags and returns fifteen fields, and every team is now afraid to change it. How do you decide where to split it, and what do you weigh when drawing hook boundaries in a shared library?
basics
~20 sSplit by concern and lifetime, not by size: each hook should own one source of truth or one subscription. Behaviour-selecting flags are the strongest signal that several hooks were fused, so extract those first and keep a thin composite for existing callers.
Your React app has several hand-rolled useReducer state machines for wizards and async flows. When does moving them to a statechart library such as XState pay for itself, and when is it over-engineering?
basics
~20 sA statechart library pays off when flows outgrow a flat status list — nested states, concurrent regions, guards and delays repeated across features, or a graph non-engineers must review. For one component with four states and six transitions, a plain reducer is cheaper and clearer.
showing 31–49 of 49