Introduction to React Query
In this page:
Why React Query Instead of Manual fetch + useState
Manually fetching data with useState and useEffect means writing your own loading/error/caching logic every time. React Query handles all of this automatically — caching results, avoiding duplicate requests, and refetching when data goes stale — behind one simple hook.
Note: React Query shines especially for data that multiple components need, or that should refresh automatically over time.
Warning: It's specifically for SERVER state (data from an API) — it's not meant to replace local UI state like form inputs or modal visibility.
Example: Why React Query Instead of Manual fetch + useState
// Run in your local React project (npm install required)
import { useQuery } from '@tanstack/react-query';
function UserList() {
const { data, isLoading, error } = useQuery({
queryKey: ['users'],
queryFn: () => fetch('/api/users').then(res => res.json()),
});
if (isLoading) return <p>Loading...</p>;
if (error) return <p>Error loading users</p>;
return <ul>{data.map(u => <li key={u.id}>{u.name}</li>)}</ul>;
}
⚠️ This example uses an npm package with no CDN build available here — run this in your local React project.
Setting Up the QueryClientProvider
React Query needs a QueryClient instance created once and provided to the whole app via QueryClientProvider, similar to Redux's Provider. This client manages the shared cache that every useQuery call in the app reads from and writes to.
Note: Create the QueryClient once at module scope, not inside a component, so it isn't recreated on every render.
Warning: Any component calling useQuery must be rendered inside the QueryClientProvider, or it will throw an error.
Example: Setting Up the QueryClientProvider
// Run in your local React project (npm install required)
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
const queryClient = new QueryClient();
function App() {
return (
<QueryClientProvider client={queryClient}>
<UserList />
</QueryClientProvider>
);
}
⚠️ This example uses an npm package with no CDN build available here — run this in your local React project.
Understanding Query Keys
A query key (an array, like [users] or [user, userId]) uniquely identifies a piece of cached data. React Query uses it to decide whether two components asking for data are asking for the SAME thing (sharing a cache entry) or different things (separate entries).
Note: Include any variables the query depends on directly in the key, like [user, userId], so React Query automatically refetches when userId changes.
Warning: Reusing the same query key for genuinely different data causes React Query to serve stale, mismatched data from the wrong cache entry.
Example: Understanding Query Keys
// Run in your local React project (npm install required)
import { useQuery } from '@tanstack/react-query';
function UserDetail({ userId }) {
const { data } = useQuery({
queryKey: ['user', userId],
queryFn: () => fetch(`/api/users/${userId}`).then(r => r.json()),
});
return <p>{data?.name}</p>;
}
⚠️ This example uses an npm package with no CDN build available here — run this in your local React project.
- Manually managing loading/error/data state alongside React Query when the library already provides all of it via useQuery's return value.
- Giving two unrelated queries the exact same query key, causing them to incorrectly share cached data.
- Forgetting to wrap the app in a QueryClientProvider, which useQuery requires.
- React Query (now TanStack Query) manages server-state: fetching, caching, and synchronizing remote data.
- useQuery(key, fetchFn) returns data, isLoading, and error automatically, without manual state management.
- A unique query key identifies each cached query, enabling automatic caching and refetching.
- The app must be wrapped in a QueryClientProvider for useQuery to work anywhere in the tree.
Requires npm install @tanstack/react-query — not available via CDN in this sandbox; works with React 16.8+.
Chapter Quiz — Complete all 10 topics to unlock
0/10 topics done
Complete these topics first: