database-zapEngineering
State Management & Data Fetching
Server state vs client state, when to use Context, Zustand, or a query library, and avoiding global-state overreach.
1 item
Links1
01NotesNote
The key distinction: server state vs client state
Most "state management" pain comes from treating these as one problem. They aren't.
- Server state is data that lives on the server and you cache locally — users, posts, anything from an API. It's asynchronous, shared, can go stale, and needs caching, revalidation, and loading/error handling. Don't manage this with
useState+useEffect. - Client state is purely local UI state — a modal open/closed, a form's current value, the active tab. This belongs in
useState/useReducer.
Server state → a query library (or the server)
- In Next.js App Router, fetch on the server wherever possible (see the Next.js note) — that's the simplest "cache."
- For client-side server state, use TanStack Query (React Query) or SWR. They give you caching, deduping, background revalidation, retries, and loading/error states out of the box. Re-implementing this with effects is how bugs breed.
- Optimistic updates and cache invalidation after mutations are first-class — use them instead of manual refetch juggling.
Client state — escalate only as needed
useStatein the component. Most state is local; keep it there.- Lift state to the nearest common parent when siblings need to share it.
useContextfor genuinely global, low-frequency values: theme, current user, locale. Caveat — every consumer re-renders when the context value changes, so don't put fast-changing state in Context.- A store (Zustand / Jotai) when you have global, frequently-updated client state that Context would re-render too aggressively. Zustand is minimal and avoids the provider-nesting and boilerplate of older solutions.
The URL is state too
Filters, tabs, pagination, search queries — put them in the URL (search params). It's shareable, survives refresh, and works with the back button. Don't reinvent it in React state.
Rules of thumb
- Don't reach for global state by default. Most state is local; global is the exception.
- Never store server data in a global client store and try to keep it fresh by hand — that's exactly what a query library does correctly.
- Derive, don't duplicate. If B can be computed from A, don't store B.