Server State vs Client State
📖 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
1import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'23function Products() {4 const queryClient = useQueryClient()56 // 1. Fetching (Server State)7 const { data, isLoading, error } = useQuery({8 queryKey: ['products'],9 queryFn: () => fetch('/api/products').then(res => res.json())10 })1112 // 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 refresh22 queryClient.invalidateQueries({ queryKey: ['products'] })23 }24 })2526 if (isLoading) return 'Loading...'2728 return (29 <div>30 {data.map(p => <div key={p.id}>{p.name}</div>)}31 <button onClick={() => mutation.mutate({ name: 'New Phone' })}>32 Add Product33 </button>34 </div>35 )36}
🏋️ Practice Exercise
- Refactor an existing
useEffectfetch to useuseQueryfrom TanStack Query. - Implement 'Optimistic Updates' where the UI updates before the server response arrives.
- Explore the 'React Query Devtools' to see how the cache works in real-time.
- 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