State Management Interview Questions

State questions are really ownership questions — where a value lives, who may change it, and what happens when two places disagree.

This topic has 23 curated State Management questions covering single source of truth, derived state, Redux patterns, caching and optimistic updates. Below are 8 of them in full, with the same answers you get in the interactive tool.

Practise all 23 State Management questions →

Difficulty breakdown

  • Easy4
  • Medium8
  • Hard10
  • Expert1

Question formats

  • Multiple choice6
  • Concept3
  • Follow-up3
  • Scenario3
  • Best practice2
  • Code review2

What these questions cover

  • architecture
  • modelling
  • redux
  • performance
  • caching
  • consistency
  • fundamentals
  • immutability
  • optimistic
  • ownership

8 example State Management interview questions

ExpertArchitecture

A team wants to move all server data into Redux "so everything is in one place". What would you argue?

That one place is the wrong goal if the two kinds of state have different requirements. Server data is a CACHE of something you do not own: it goes stale, needs revalidation, deduplication, retry, per-query loading and error states, and garbage collection. Reimplementing those in reducers is a large amount of code that a data library already provides and tests. Client state — modal open, wizard step, draft form, selection — has none of those needs and belongs in local state, the URL, or a small store. The honest counter-argument is coordination: when a mutation must update several caches at once, having everything in one store looks simpler; the answer there is cache invalidation by tag rather than manual reducers. I would keep server data in a query cache, keep genuinely global client state in a store, and put URL-shaped state in the URL.

Expert-level because it requires arguing against a reasonable-sounding position with specifics, and acknowledging the real case for it.

EasyBest practice

A new piece of state is needed. What is your decision order for where it should live?

Work outwards from the smallest scope that works. Can it be DERIVED from something you already have? Then do not store it at all. Is it used by one component? Local state. Used by a few components in one subtree? Lift it to their nearest common parent. Does it describe what the user is looking at — filters, tab, selected id, page? Put it in the URL, which gives sharing, back/forward and reload recovery for free. Is it server data? A query cache, not hand-rolled state. Is it genuinely global and slow-changing — theme, locale, session? Context or a small store. Reaching for the global store first is the common mistake, and it is the hardest to undo later.

Easy but high-leverage: a decision order is more useful to a junior candidate than a list of tools, and the derive-first step eliminates a lot of state entirely.

HardWrite code

Add undo/redo to an editor. What state model makes this tractable?

The snapshot-versus-command trade is the substance: snapshots are trivially correct and memory-hungry, commands are compact and easy to get subtly wrong.

MediumCode review

Review these selectors

const useVisible = () => useSelector((s) => s.items.filter((i) => i.visible));
const useTotal   = () => useSelector((s) => s.items.reduce((n, i) => n + i.price, 0));

`useVisible` returns a NEW array every call, so the default reference check always reports a change and every consumer re-renders on any store update — including updates to unrelated slices. Memoize it with `createSelector` so the array identity is stable while the inputs are unchanged, or pass a shallow-equality comparator. `useTotal` is fine as written: it returns a primitive, which compares by value, so it only re-renders when the number actually changes. The contrast between the two is the lesson — deriving a primitive is safe, deriving an object or array is not.

Reviewing both together is deliberate: the same pattern is a bug in one and correct in the other, and knowing why is the point.

EasyConcept

What does "single source of truth" mean in practice, and what goes wrong without it?

It means every piece of information has exactly one authoritative home, and everything else derives from it rather than copying it. Without it you get two copies that can disagree: the same user’s name rendered differently in two places, a count that does not match the list it counts, a form that shows stale data after a save. Those bugs are hard to fix because the code is not wrong anywhere in particular — it is only wrong in aggregate. In practice it means deriving values during render instead of storing them, keying server data by id in one cache rather than embedding copies, and resisting the instinct to "sync" two pieces of state with an effect, which institutionalises the duplication instead of removing it.

What makes these bugs expensive is that no individual line is wrong — each copy updates correctly, they just update at different times, so the defect only exists in the relationship between them. That is why the fix is structural rather than a patch: derive instead of store, and the disagreement becomes impossible rather than unlikely. The instinct to reconcile two copies with an effect is the trap, because it makes the duplication permanent and adds a render where the two are visibly out of step.

HardDebugging

An optimistic "like" sometimes leaves the UI permanently wrong. Find the flaw

async function like(id) {
  setLiked((s) => ({ ...s, [id]: true }));
  try { await api.like(id); }
  catch { setLiked((s) => ({ ...s, [id]: false })); }
}

The rollback restores a guessed value rather than the previous one. If the item was already liked and the request fails, this sets it to false — inventing a state that never existed. It is also unsafe under concurrency: two rapid toggles interleave and the rollback of the first clobbers the result of the second. Fix by snapshotting the previous value before the mutation and restoring exactly that on failure, keying the rollback to the specific mutation so a stale one cannot undo a newer change, and revalidating from the server afterwards so the cache converges on truth rather than on your guess.

The general rule for optimistic updates: capture the previous state, roll back to it specifically, and settle by revalidating rather than by assuming.

MediumFollow-up

You put filters in the URL. What happens when there are thirty of them?

You hit practical limits. URLs have length constraints in some browsers, proxies and analytics tools; a very long query string is unreadable and unshareable in practice even when technically valid; and every filter change becomes a history entry unless you replace rather than push, so the back button turns into an undo log the user did not want. Options: keep only the filters that meaningfully identify the view in the URL and hold ephemeral ones in memory; encode the set compactly rather than one parameter each; or store the full filter set server-side and put a short id in the URL, which keeps sharing working and removes the length problem. Use `replaceState` for incremental changes and `pushState` only for navigations the user would expect to go back from.

The history-entry consequence is the one that produces a visible UX bug, and it is rarely considered when the pattern is first adopted.

HardMultiple choice

How can Redux Toolkit let you write `state.items.push(x)` in a reducer?

You mutate a proxy, not the store. Immer records the changes and structurally shares everything untouched, so the result is a genuinely new object with unchanged subtrees reused. Returning a new value AND mutating the draft in the same reducer is the mistake to avoid.

The remaining 15 State Management questions — plus mock interviews, spaced revision and progress tracking — are in the free interview prep workspace.

Related interview topics