Question presented to candidate: "How would you approach state management for a large React app? Walk me through the decision."
What a strong answer should cover:
- The reframe that answers the question: separate server state from client state. Most of what people put in a global store is cached server data — it needs fetching, deduplication, invalidation and staleness rules, not storage.
- Once server state is handled by a query library, the genuinely global client state left over is usually small: theme, auth session, a cart, UI preferences.
- The ladder: local state → lifted state → composition → Context → a store, adopting each only when the previous one stops working.
- Context is transport, not a store — no selectors, so every consumer re-renders.
- What a store adds that Context cannot: selector-based subscriptions, so a component re-renders only for the slice it reads.
- The realistic options and what distinguishes them: Redux Toolkit (conventions, devtools, large teams), Zustand (minimal, hook-based), Jotai (atomic, bottom-up), and
useSyncExternalStoreas the primitive they are all built on. - URL state is the forgotten category — filters, tabs, and pagination usually belong in the query string, where they are shareable and survive a refresh.
- Anti-pattern: one giant store holding everything, which makes change frequency the maximum of everything in it.
Clarifying questions expected:
- "How much of this is server data versus genuinely client-only state?"
- "How large is the team — do we need enforced conventions and devtools?"
- "Does any of it belong in the URL?"
Code / implementation expected: Optional. A small store with a selector demonstrates the point that Context cannot.