← Back to React Course | Chapter 10: Data Fetching & Async | Lesson 5 of 10

Introduction to React Query

React Query is like a smart librarian who remembers what books you already borrowed, so you don't have to walk back to the shelf every time you ask for the same one.

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

markup
// 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

markup
// 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

markup
// 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.

Common Mistakes
  1. Manually managing loading/error/data state alongside React Query when the library already provides all of it via useQuery's return value.
  2. Giving two unrelated queries the exact same query key, causing them to incorrectly share cached data.
  3. Forgetting to wrap the app in a QueryClientProvider, which useQuery requires.
Chapter Summary
  • 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.
Browser Support

Requires npm install @tanstack/react-query — not available via CDN in this sandbox; works with React 16.8+.

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.