intermediate

Server state vs client state

Separate remote cached data from UI-only interaction state, form drafts, selections, and ephemeral flags.

Server state is remote, asynchronous, shared, and eventually consistent: lists, details, permissions from APIs. Client state is UI-owned and synchronous: selected tab, modal open, form draft before submit, optimistic overlay.

| Dimension | Server state | Client state | |-----------|--------------|--------------| | Source of truth | Backend | Browser UI | | Staleness | Expected | N/A | | Tooling | TanStack Query, SWR, RTK Query | useState, Zustand, Redux | | Invalidation | Keys, tags, refetch | Local setState |

Do not mirror entire API responses into Redux if a cache library already handles freshness, deduplication, and background refetch. Keep client state for what the server does not know yet.

The trade-off is fewer libraries versus mental overhead: two categories of state mean two invalidation models, but mixing them in one store hides bugs.

On interviews: explain why a product list belongs in a query cache while "sort column clicked" stays local.

Common pitfalls: Redux as a manual fetch cache, duplicating server data in two places, and treating loading/error as permanent store shape instead of request metadata.

Checklist:

  • Server truth stays on the server.
  • Cache libraries own remote freshness.
  • Client store for UI-only coordination.
  • Sync writes back through mutations + invalidation.