Quiz: State Management
Covers the three categories of state, React Query cache design, targeted invalidation, and optimistic updates. Reference: ADR: State Management · ADR: Idempotency & Optimistic Updates.
Question 1: Three categories of state
Senior
Show answer
- Server state → React Query cache (wallet data, balances, transactions). It's a cache of someone else's data, so it needs staleness, refetching, and invalidation: exactly what React Query provides.
- Global client state → Zustand (session, theme). Cross-cutting, but owned by the client.
- Local UI state →
useState(form inputs, modal open/close). Belongs to one component.
The rule: use the most local storage that works. Form state never goes in Zustand; wallet data never goes in useState. Putting server data in useState means you hand-roll caching and invalidation badly; putting form state in a global store creates spooky action at a distance.
Question 2: Targeted invalidation
Senior
['accounts', walletId]), and what does that let a transfer do that a flat cache couldn't?Show answer
Structured keys let you invalidate precisely. A transfer can invalidate ['accounts', fromId] and ['accounts', toId] and leave the transaction feed, balance history, and unrelated wallets alone: only the data that actually changed is refetched.
A flat or coarse cache forces a choice between two bad options: invalidate everything (a thundering refetch and UI flicker on every mutation) or invalidate nothing (stale balances). Parameterised keys give you a scalpel instead of a sledgehammer.
Question 3: Optimistic updates: the three callbacks
Senior
onMutate / onError / onSettled for an optimistic transfer. Why must you cancelQueries first, and why invalidate in onSettled even on success?Show answer
onMutate:cancelQueriesfirst (so an in-flight refetch can't land after your optimistic write and clobber it), snapshot the current cache, then apply the expected result so the UI updates instantly.onError: restore the snapshot, roll back so the UI never shows a permanently wrong state.onSettled: invalidate the affected keys regardless of success or failure.
Why invalidate even on success: the optimistic value is a guess. The server may have applied a fee, rounded, or reordered. You don't trust your guess or your rollback: on settle you ask the server for the truth. Instant feedback (optimism) plus eventual consistency (invalidate) is the whole pattern.
Question 4: Optimistic state surviving unmount
Staff
Show answer
The snapshot lives in the React Query cache, not in component state. So when the component unmounts on navigation, the snapshot and the in-flight mutation survive: the rollback (or invalidation) still has something to act on when the request settles.
What would break it: holding the snapshot in useState inside the page component. On unmount that state is gone, so an error after navigation has nothing to roll back to, and the cache is left in the optimistic (possibly wrong) state. Stable cache keys + cache-held snapshots are what make it survive.