All topics
Stateintermediate

Async Data Fetching with React Query / TanStack Query

Learn how server-state libraries like TanStack Query handle caching, background refetching, and deduplication that plain useEffect fetching doesn't.

TanStack Query (formerly React Query) is built on the recognition that server state — data owned by a remote source and merely cached on the client — has fundamentally different needs than client state like form inputs or UI toggles. It can go stale, needs refetching, may be requested by multiple components simultaneously, and benefits from caching across navigations.

TanStack Query is like a well-run reference desk at a library: if five people ask for the same book (same query key) at once, the librarian fetches it a single time and hands a copy to everyone, keeps a recently-used shelf (cache) so the next request doesn't need a fresh trip to the stacks, and periodically checks if a newer edition (background refetch) has come out.

Key Concepts

1
The core hook, useQuery(queryKey, queryFn), handles loading/error/success states automatically, caches results keyed by queryKey, deduplicates simultaneous requests for the same key, and can automatically refetch in the background on window refocus, network reconnect, or a configured stale time — all without hand-written useEffect and useState boilerplate for each of those concerns.
useQuery(queryKey, queryFn)queryKeyuseEffectuseState
2
Writing the equivalent behavior manually with useEffect/useState typically misses several of these features (no caching between component mounts, no deduplication of parallel identical requests, no automatic background refresh) and requires significant custom code to add them, which is why interviewers view 'roll your own data fetching with useEffect' as generally inferior to a dedicated server-state library for anything beyond the simplest cases.
useEffectuseState
3
A well-prepared candidate distinguishes server state (owned remotely, cached locally, potentially shared across the app) from client state (owned entirely by the UI, like a modal's open/closed flag), and explains why mixing the two into a single state management approach (like putting all fetched data into Redux) often duplicates caching logic that a dedicated library already solves well.
server stateclient state