Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 3

Integrating TanStack Query into React

Recommended resources

Welcome to your third lesson!

In our previous session, we established the "why" behind TanStack Query. We explored the concept of server state, the stale-while-revalidate caching strategy, and the roles of staleTime and gcTime in managing the cache lifecycle. It was all about the theory.

Today, we move from theory to practice. This lesson covers the essential first step in using TanStack Query in any React project: setting it up correctly. We will install the necessary packages and then learn how to configure the two core components that make the library work: the QueryClient and the QueryClientProvider. By the end of this lesson, you will have a solid foundation, ready to start fetching data.

1. Installation

First things first, let's get the required packages into our project. We need two:

  • @tanstack/react-query: The core library that provides all the hooks and logic.
  • @tanstack/react-query-devtools: An optional but highly recommended package that gives you a powerful tool to inspect your cache and debug your queries during development.

TanStack Query v5 + React + Vite - DEV Community

This article provides a clear guide for starting a React project with Vite and installing TanStack Query. We'll use it to walk through the initial setup steps.

Please read the section titled 'Installing React Query'. It shows the command to install both the core library and the devtools. You can skip the project creation part if you already have a project ready.

As the article notes, the command to run in your project's terminal is:
npm install @tanstack/react-query @tanstack/react-query-devtools

With the packages installed, we can now configure them.


2. Creating the QueryClient

The QueryClient is the brain of TanStack Query. It's an object that holds the cache and manages all the background logic for fetching, caching, and revalidating your data.

You only need one QueryClient instance for your entire application.

Here's how you create it:

import { QueryClient } from '@tanstack/react-query';

// Create a client
const queryClient = new QueryClient();

A crucial best practice is to create this client instance outside of any component. If you create it inside a component, a new client (and a new, empty cache) would be created on every render, which completely defeats the purpose of caching.

One of the most powerful features of the QueryClient is that you can provide default options that will apply to all queries in your app. This is where the concepts from our last lesson, like staleTime, come into play.

import { QueryClient } from '@tanstack/react-query';

// Create a client with default options
const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      staleTime: 1000 * 60 * 5, // 5 minutes
    },
  },
});

In this example, we're telling TanStack Query that by default, all fetched data should be considered fresh for 5 minutes. This prevents unnecessary refetches for data that we know doesn't change very often. You can, of course, override this default for any specific query later on.


3. Providing the Client with QueryClientProvider

Now that we have a queryClient instance, we need to make it available to all the components in our application. We do this using the QueryClientProvider, which leverages React's Context API.

You need to wrap your root component (usually in your main.jsx or index.js file) with QueryClientProvider and pass your queryClient instance to it as a prop.

// In main.jsx or index.js
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import App from './App';

const queryClient = new QueryClient();

ReactDOM.createRoot(document.getElementById('root')).render(
  <React.StrictMode>
    <QueryClientProvider client={queryClient}>
      <App />
    </QueryClientProvider>
  </React.StrictMode>,
);

This provider ensures that any component in your app can access the client and, by extension, the cache. Hooks like useQuery and useMutation will "find" this client via context and use it to manage their state.

What happens if you forget this step?

TanStack Query Error: No QueryClient Set
This error, "No QueryClient set, use QueryClientProvider to set one," is exactly what you will see if a TanStack Query hook is used in a component that isn't a descendant of QueryClientProvider.

This is one of the most common mistakes for beginners. The hooks will fail silently or throw an error like the one above because they have no QueryClient to communicate with.

Beginner's Guide to React Query

To reinforce this point, let's look at a guide that explicitly calls out this common pitfall.

Please read the short section titled 'Forgetting to wrap your app in QueryClientProvider' under 'Common mistakes and best practices'. It emphasizes why this step is so critical.


4. Putting It All Together (with Devtools!)

Let's combine everything into a complete, production-ready setup in main.jsx. This includes creating the client, providing it to our app, and adding the ReactQueryDevtools component.

TanStack Query v5 + React + Vite - DEV Community

The first article we looked at provides a perfect, complete example of the setup in main.jsx. Let's study it.

Read the sections 'Setting Up the Query Client' and 'Understanding the Configuration'. Pay close attention to the full main.jsx code block. It shows the QueryClient instantiation, the QueryClientProvider wrapper, and how the ReactQueryDevtools are included.

As you saw in the article, the final main.jsx looks like this:

// src/main.jsx
import React from 'react'
import ReactDOM from 'react-dom/client'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { ReactQueryDevtools } from '@tanstack/react-query-devtools'
import App from './App'

// Create a client
const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      staleTime: 1000 * 60 * 5, // 5 minutes
    },
  },
});

ReactDOM.createRoot(document.getElementById('root')).render(
  <React.StrictMode>
    <QueryClientProvider client={queryClient}>
      <App />
      <ReactQueryDevtools initialIsOpen={false} />
    </QueryClientProvider>
  </React.StrictMode>,
)

The <ReactQueryDevtools /> component, when placed inside the provider, gives you a floating icon in your app during development. Clicking it opens a panel where you can see every query, its data, its status (fresh, stale, fetching), and much more. It is an indispensable tool for understanding how your cache behaves.

TanStack Query Devtools in Action
An example of the TanStack Query Devtools panel. It shows a 'users' query, its 'fresh' status, and the data it holds. This gives you direct insight into the cache.

Conclusion

Congratulations! You've now learned how to properly integrate TanStack Query into a React application. This setup is a one-time task for most projects, but getting it right is fundamental to everything that follows.

Key Takeaways:

  • You need to install @tanstack/react-query and @tanstack/react-query-devtools.
  • The QueryClient is the core of the library, managing the cache. You should create a single instance of it outside your components.
  • You can set application-wide defaults for staleTime and other options when creating the QueryClient.
  • The QueryClientProvider uses React's Context to make the client instance available throughout your app. Forgetting to wrap your app with it is a common source of errors.
  • ReactQueryDevtools is an essential development tool that provides visibility into the cache.

Next Lesson Preview:

With the foundation now firmly in place, we're ready for the main event. In the next lesson, you will learn how to use the useQuery hook to fetch, cache, and display data from a server, and see the stale-while-revalidate strategy in action.