- React
- State Architecture, Store Subscriptions, and Server Cache
- State Architecture: Taxonomy & Categorization
State Architecture: Taxonomy & Categorization
Modern React state belongs to five distinct categories: local UI state (useState), shared client state (Zustand/Context), server cache state (TanStack Query), URL state (searchParams), and persistent device state (localStorage). Choosing the wrong bucket causes synchronization bugs and unnecessary re-renders.
Key Learning Objectives
Classify application state into local, shared client, server cache, URL, and persistent categories.
Recognize why caching remote API data in Redux or Context violates the single source of truth.
Leverage URL search params as the authoritative state for pagination, filters, and modals.
Design lean component architectures that avoid global state bloat.
The Interview Problem & Context
Given an e-commerce product search page with pagination, filters, a shopping cart, and search queries, how should each piece of state be categorized and managed?
1// Recommended state placement taxonomy2interface AppStateArchitecture {3 // 1. URL State: Bookmarkable, shareable, survives refreshes4 // Handled by: useSearchParams / router5 urlState: {6 query: string; // ?q=laptop7 page: number; // ?page=28 filterTag: string; // ?tag=electronics9 };1011 // 2. Server Cache State: Asynchronous, owned by backend, needs invalidation12 // Handled by: TanStack Query (React Query) / SWR / RTK Query13 serverState: {14 products: Array<{ id: string; name: string; price: number }>;15 isLoading: boolean;16 isStale: boolean;17 };1819 // 3. Shared Global Client State: Ephemeral client-only domain state20 // Handled by: Zustand / Context API21 globalClientState: {22 cartItems: Array<{ productId: string; quantity: number }>;23 isCartDrawerOpen: boolean;24 };2526 // 4. Local Component State: Isolated UI micro-interactions27 // Handled by: useState / useReducer28 localUIState: {29 isHovered: boolean;30 activeDropdownIndex: number | null;31 };32}
Deep Architectural Explanation
The 5 Types of State in Modern React
In early React applications, developers put every piece of state into a single monolithic Redux store. Modern frontend architecture categorizes state by its owner, lifetime, and synchronization requirements:
| State Type | Characteristics | Recommended Solution |
|---|---|---|
| URL State | Bookmarkable, shareable via link, browser back/forward | useSearchParams / Next.js router |
| Server State | Owned by backend, async fetch, caching, deduping, TTL | TanStack Query, SWR, RTK Query |
| Global Client State | Synchronous, shared across unrelated branches, client-only | Zustand, Redux Toolkit, Context |
| Local UI State | Scoped to a single widget or parent-child subtree | useState, useReducer |
| Persistent State | Survives browser close, tied to hardware/user device | localStorage, IndexedDB |
Architectural Rule:
Never duplicate server state in client state. If the data originates from a REST or GraphQL endpoint, treat it as a remote cache using TanStack Query. Only store purely client-owned UI state in Zustand or Context.
Common Interview Traps & Pitfalls
Duplicating filter and search values in useState instead of synchronizing with URL search params.
Manually managing fetch, loading, error, and caching logic in global Redux slices.
Lifting local UI state (like dropdown open/close) to global stores, triggering app-wide re-renders.
Senior Interviewer Follow-Up Probes
How does TanStack Query handle stale-while-revalidate caching under the hood?
When would you choose URL query parameters over local component state for a modal dialog?
What are the memory and re-render implications of keeping high-frequency state in React Context?
Frequently Asked Interview Questions
When should state be put in the URL query string?
Any state that determines what content is rendered and should be shareable or preserve history on browser back/forward navigation—such as pagination, sorting, search queries, active tab IDs, and open filter drawers.
How do you determine if state should be local or global?
Start local with useState at the lowest common ancestor in the tree. Only lift state up to global stores if two or more distant, decoupled components need to read or mutate the exact same data.
Does React 19 change state management recommendations?
React 19 Server Components and Actions allow server data fetching and mutations directly without client-side fetching libraries in full-stack frameworks, but client state taxonomy principles remain identical for interactive UI.
Why is localStorage not a replacement for client state managers?
localStorage access is synchronous and blocks the main thread on large payloads. Furthermore, changes to localStorage do not automatically trigger React component re-renders unless wrapped in a custom hook using useSyncExternalStore or window storage events.
What is the difference between derived state and persistent state?
Derived state is computed synchronously during render from existing props or state (e.g., filteredList = list.filter(...)) and should never be stored. Persistent state is written to browser storage and restored across sessions.
