Server State vs Client State: Clearing the Confusion

date
Jul 10, 2025
slug
server-state-vs-client-state-clearing-the-confusion
status
Published
tags
react
summary
type
Post
I often work with colleagues on a Next.js app using TanStack Query, and they confuse client state with server state—probably because they managed everything with Redux in the past. With Redux, you fetch API data into a local store and share it globally , but you lose control over caching or retry. In reality, API data is server state and needs proper caching, in-flight deduplication, and synchronization—features Redux doesn't provide out of the box. That’s why most teams choose TanStack Query: any component simply calls the API via useQuery, and the library handles caching, updating, and sharing results.
In this article we’ll:
  1. Define client state vs server state
  1. why we need a data fetching library
  1. Demonstrate shared queries across components

Client State vs Server State

Client state lives only in the browser:
  • modals open or close state
  • Form values, errors, validations
  • Theme toggles, animations
States like these are deterministic, synchronous and perfect to be managed by useState (if only one component needs it) or context and Zustand (when multiple components need it). It only lives in the browser and resets when users refresh the page.
Server state comes from an API:
  • Fetched resources (users, posts)
  • Mutations (POST/PUT/DELETE)
  • Paginated or infinite lists
They are asynchronous, shared, and requiring cache invalidation.

Why do we need a Data Fetching Library like tanstack query?

In practice, three scenarios make a data fetching library indispensable:
  1. cache: Imagine both a parent component and a grandchild component need the same API data. Instead of manually fetching once and passing props down, each component can call the API via useQuery with the same key. TanStack Query caches results and deduplicates in-flight requests, so you never trigger duplicate network calls. Here is a code example:
    1. cache invalidation: After you mutate data—say, submitting a new policy claim—you return to your list and expect updated statuses without reloading the page. With TanStack Query, you simply invalidate the relevant query (queryClient.invalidateQueries(['claims'])), and it refetches fresh data automatically. There is a simple code example:
      1. retries: Network failures happen. TanStack Query provides configurable retry policies out of the box (global or per-query),
      With these features built‑in, you no longer need to manage caching, deduplication, or retries yourself—TanStack Query handles it, letting you focus on rendering your UI.

      Conclusion

      Stop treating API data as simple Redux state. Use TanStack Query to manage server state—caching, deduplication, error handling—all out of the box. You can simply manage client-only state with the context or a lightweight store, such as redux.
       

      © ming 2021 - 2025