Server State vs Client State

0/3 in this phase0/36 across the roadmap

📖 Concept

One of the biggest shifts in modern React is realizing that most global state is actually just a cache of your database (Server State).

Client State: Data needed only by the UI (e.g., is the modal open? which theme is active?). Use useState, Zustand, or Context.

Server State: Data that comes from an API (e.g., list of users, product details). This data is "asynchronous" and "stale" as soon as it arrives.

The modern solution: TanStack Query (React Query) Instead of fetching data and putting it into Redux, you use React Query to manage it. It handles:

  • Caching (so you don't fetch the same data twice).
  • Deduping (multiple components can request the same data, but only one request is sent).
  • Background re-fetching (keeping data fresh).
  • Mutation handling (updating data on the server).

💻 Code Example

codeTap to expand ⛶
1import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
2
3function Products() {
4 const queryClient = useQueryClient()
5
6 // 1. Fetching (Server State)
7 const { data, isLoading, error } = useQuery({
8 queryKey: ['products'],
9 queryFn: () => fetch('/api/products').then(res => res.json())
10 })
11
12 // 2. Updating (Mutation)
13 const mutation = useMutation({
14 mutationFn: (newProduct) => {
15 return fetch('/api/products', {
16 method: 'POST',
17 body: JSON.stringify(newProduct)
18 })
19 },
20 onSuccess: () => {
21 // 3. Invalidate cache to trigger a background refresh
22 queryClient.invalidateQueries({ queryKey: ['products'] })
23 }
24 })
25
26 if (isLoading) return 'Loading...'
27
28 return (
29 <div>
30 {data.map(p => <div key={p.id}>{p.name}</div>)}
31 <button onClick={() => mutation.mutate({ name: 'New Phone' })}>
32 Add Product
33 </button>
34 </div>
35 )
36}

🏋️ Practice Exercise

  1. Refactor an existing useEffect fetch to use useQuery from TanStack Query.
  2. Implement 'Optimistic Updates' where the UI updates before the server response arrives.
  3. Explore the 'React Query Devtools' to see how the cache works in real-time.
  4. Set up a 'Stale Time' of 5 minutes and notice how navigating back to a page doesn't trigger a new network request.

⚠️ Common Mistakes

  • Mixing Client State (Zustand) and Server State (React Query) unnecessarily.

  • Not providing a unique queryKey, leading to data being cached in the wrong place.

  • Manually managing loading/error states when React Query provides them for free.

💼 Interview Questions

🎤 Mock Interview

Practice a live interview for Server State vs Client State