FSD Frontend System Design

Part III β€” The Speed Β· Lesson 6.1

State Management

In one lineSort state by who owns it β€” server, URL, or client β€” and most of the hard problem disappears.

Where you've seen itCopying a filtered search URL into Slack and having a colleague open the identical view.

  • Time17 min
  • DiagramState ownership map + the scope ladder
  • Chapter6 Β· Database & Caching

Diagram

diagram
FOUR KINDS OF STATE β€” different owners, different tools

  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
  β”‚ SERVER STATE    users, orders, feed                        β”‚
  β”‚   owner: the backend. You hold a CACHE of it (6.9).        β”‚
  β”‚   tool: React Query / RTK Query / SWR / Apollo             β”‚
  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
  β”‚ URL STATE       filters, page, sort, open tab, search term β”‚
  β”‚   owner: the address bar. Shareable, back-button-able.     β”‚
  β”‚   tool: the router                                         β”‚
  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
  β”‚ CLIENT STATE    theme, sidebar open, wizard step, cart     β”‚
  β”‚   owner: your app. Genuinely global, genuinely local.      β”‚
  β”‚   tool: useState / Context / Zustand / Redux               β”‚
  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
  β”‚ FORM STATE      field values, touched, errors              β”‚
  β”‚   owner: the form. High-frequency, short-lived.            β”‚
  β”‚   tool: react-hook-form / Formik                           β”‚
  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

  Most "state management is hard" complaints are server state
  being stored as if it were client state.
diagram
THE SCOPE LADDER β€” climb only when forced

  useState                one component            ← start here
      β”‚ needed by a child several levels down
      β–Ό
  props / composition     pass it down             ← often enough
      β”‚ needed by many, changes rarely
      β–Ό
  Context                 theme, auth, locale      ← re-renders all
      β”‚                                              consumers
      β”‚ needed by many, changes often
      β–Ό
  external store          Zustand / Redux          ← selective
                                                     subscriptions

  Skipping to the bottom rung on day one is the classic over-engineering.
diagram
WHY CONTEXT IS NOT A STORE

  <Provider value={{user, cart, theme}}>
       β”‚  any field changes ──► EVERY consumer re-renders
       β”‚
  Zustand/Redux: useStore(s => s.cart.count)
       β”‚  only components selecting cart.count re-render

How it works

  1. Classify first. Ask "who is the source of truth?" Server state gets a caching library, not a global store.
  2. Push filters and pagination into the URL β€” you get shareability, deep links, and back-button behaviour for free.
  3. Keep client state as local as possible, lifting only when a second consumer genuinely appears.
  4. Use Context for low-frequency, wide-reach values (theme, auth, locale); use a store with selectors for anything that changes often.
  5. Derive, don't duplicate. Totals, filtered lists, and counts should be computed from state, never stored alongside it.

Trade-offs

ToolFitsCost
useStateLocal UIProp drilling if over-lifted
ContextTheme, auth, localeRe-renders all consumers
ZustandGlobal client state, small APIAnother concept in the codebase
Redux ToolkitLarge apps, devtools, middlewareBoilerplate, learning curve
React QueryAll server stateNot for client-only state

Interview angle

"Which state management library would you choose?"

  • Reframe first: most of the state is server state, so the real answer is a caching library plus the URL.
  • What's left is genuinely small β€” theme, modals, cart β€” and useState plus one lightweight store usually covers it.
  • Choose Redux when you need time-travel debugging, middleware, or a large team needing strict conventions β€” not by default.

Recap

  • Server, URL, client, form β€” classify before choosing a tool.
  • Filters and pagination belong in the URL, not in a store.
  • Context broadcasts; stores let components subscribe selectively.