Introduction to React Query
In this page:
const queryClient = new QueryClient();
<QueryClientProvider client={queryClient}>
<App />
</QueryClientProvider>
const { data, isLoading, error } = useQuery({
queryKey: ["key", id],
queryFn: fetchFunction,
});
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.
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.
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).
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: