Beginner’s Guide to React Query (Now Tanstack Query)

Yihua Zhang
Yihua Zhang
hero image

If you've ever tried to fetch data in React, you’ve no doubt come across the creeping mess of useEffect, useState, and nested logic just to load something simple from an API.

You write a few lines, and suddenly you’re juggling loading states, handling errors, retrying failed calls, and wondering if the data's even fresh anymore.

It feels like there should be a better way, right?

Well, there is, and that’s exactly what React Query was built to solve. It completely changes how you think about server state in your app.

It’s had a name change, but it’s still a core part of a growing ecosystem of tools reshaping how React apps handle data.

In this guide, we’ll walk through what React (or TanStack) Query actually is, how it works, and why it’s quietly become one of the most useful tools in the modern React toolbox.

Sidenote: If you want to learn more about React and how to use it, check out my complete React Developer course:

learn react

This is the only React JS bootcamp course you need to learn React, build advanced large-scale apps from scratch, and get hired as a React Developer in 2025.

Graduates from this program are now working at Google, Tesla, Amazon, Apple, IBM, Uber, Facebook, Shopify + other top tech companies. There’s no reason why you couldn’t do the same!

With that out of the way, let’s get into this 5-minute tutorial…

What is React Query? (aka TanStack Query)

Let’s start with what React Query actually is because it’s not just another utility library you slap into a project and forget about.

React Query helps you manage server state in your React app. That means any data that lives on a remote server such as user info, product listings, or anything fetched from an API.

Normally, this kind of data is handled with useEffect, useState, and a growing tangle of logic. One query turns into several states, retries, refreshes, and loading spinners scattered across components.

It works but it’s fragile, repetitive, and hard to scale cleanly.

React Query gives you a better approach because it lets you declaratively fetch, cache, and keep your data in sync. You say what you want and how fresh it should be, and React Query handles the fetch, the retries, the caching, and the background updates automatically.

No more boilerplate. No more guessing when to refetch. And no need for Redux or Context just to share API data across components.

Why the name changed

React Query is now officially called TanStack Query.

tanstack query

The tool is the same, the API is unchanged, and the functionality hasn’t gone anywhere. This wasn’t an acquisition or a major rewrite. It’s just a unified rebrand.

React Query was created by Tanner Linsley who is the same developer behind React Table, React Charts, and other libraries now grouped under the TanStack name. It’s just a rename to recognize the creator.

That said, most developers still call it React Query. You’ll see both names used in blog posts, YouTube tutorials, and Stack Overflow answers. And honestly, either is fine. They both point to the same library, and everything you’ll learn here applies to both.

Now that you know what it is and why the name changed, let’s look at how to actually use it.

How to install and set up React Query

Before using React Query, you’ll need to install the package and set up a few things. The good news is, once it’s in place, you rarely have to touch this setup again.

Start by installing the package with npm:

npm install @tanstack/react-query

Once that’s installed, the next step is to create something called a QueryClient. This is the part of the library that handles all your fetching logic, caching, and background syncing behind the scenes.

You only need one of these for your app, and you typically set it up at the top level of your component tree.

Here’s the basic setup:

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

const queryClient = new QueryClient()

function App() {
  return (
	<QueryClientProvider client={queryClient}>
  	<YourApp />
	</QueryClientProvider>
  )
}

The QueryClientProvider makes the client available to your entire app, which is how useQuery and other hooks can access and manage data consistently across components.

Important: If you forget to wrap your app with this provider, nothing will work. If you’re seeing undefined or nothing loading, double-check this setup first.

Once you’ve got this in place, you’re ready to start using useQuery in your components.

How to fetch data with useQuery

The useQuery hook is the simplest way to fetch data with React Query, as it handles all the heavy lifting such as fetching, caching, re-fetching, error handling, and background updates.

For example

Here’s an example using the JSONPlaceholder API:

import { useQuery } from '@tanstack/react-query'

function Posts() {
  const { data, isLoading, error } = useQuery({
	queryKey: ['posts'],
	queryFn: () =>
  	fetch('https://jsonplaceholder.typicode.com/posts').then(res =>
    	res.json()
  	),
  })

  if (isLoading) return <p>Loading...</p>
  if (error) return <p>Something went wrong</p>

  return (
	<ul>
  	{data.map(post => (
    	<li key={post.id}>{post.title}</li>
  	))}
	</ul>
  )
}

So let’s break this code block down, so we can see what’s happening.

The useQuery hook takes an object with two key properties:

  • queryKey. This is a unique identifier for this query. It’s used internally for caching and tracking data. This should always be an array, even if it only contains one item, because you can add parameters to it later (like filters or IDs)
  • queryFn: This is a function that does the actual data fetching. This can be fetch, axios, or any async function that returns your data

The values returned from useQuery such as data, isLoading, and error, all make it easy to handle every state your UI might be in, without writing your own flags or try/catch logic.

For example

One of the most useful features is caching. This is because if you navigate away from the component and come back later, React Query will show cached data instantly while silently refetching in the background.

That means fewer loading spinners, less waiting, and a much smoother experience.

Handy right?

Common mistakes and best practices

React Query handles a lot for you, but like any powerful tool, it’s easy to trip up if you don’t fully understand how it works. Here are some of the most common mistakes beginners run into and how to avoid them.

Forgetting to wrap your app in QueryClientProvider

We mentioned before but it’s worth listing here as it's probably the most common mistake, and it's an easy one to make.

If you forget to wrap your component tree with QueryClientProvider, then none of the React Query hooks will work. You won’t get an error that says “wrap this in a provider”. Instead, things just silently fail.

If you see useQuery returning undefined or nothing happening at all, this is the first thing to check.

Using it for local state

React Query is made for server state i.e. data that comes from a backend and needs to stay in sync with the server.

It's not a replacement for useState or useReducer when you're managing things like form inputs, toggle flags, or local UI state. And so trying to use it for those things will just complicate your code.

This means that if the data doesn’t come from a server, React Query probably isn’t the right fit.

Hardcoding query keys

Query keys are more than just labels, they’re what React Query uses to cache and track your data. This means that if you fetch similar data with the same key but different parameters (like two different users or pages), React Query will reuse the cached result unless the key changes.

So if you want to avoid stale or incorrect data, use a dynamic key when your query depends on something dynamic:

useQuery({
  queryKey: ['user', userId],
  queryFn: () => fetchUser(userId),
})

Not handling stale or background data updates

React Query automatically caches your data. By default, this data is considered 'stale' immediately (meaning it's available from cache, but TanStack Query will try to refetch it in the background on events like component remount or window focus to keep it up-to-date).

This can catch you off guard if you’re not expecting it, especially if your backend is slow or returns different data frequently.

You can adjust this behavior with options like staleTime (how long data is considered fresh) and refetchOnWindowFocus. But in most cases, the defaults are smart enough to give your users fresh data without extra code.

Overengineering with Redux or Context

One of the biggest benefits of React Query is that you don’t need global state tools like Redux just to manage API data.

This is because React Query already gives you caching, shared state, and reactivity between components, and so trying to layer Redux or Context on top of it for the same data can lead to duplicated logic and confusion. It’s best to think of React Query as your go-to for any data that’s fetched and shared across components, because it already does the job.

Treating React Query like an imperative data-fetching utility

A common mental trap is to think of React Query as just a cleaner way to fetch data, almost as if it’s a slightly nicer useEffect. But using it like this misses what makes it powerful.

This is because React Query isn’t just a data loader you control step-by-step. It’s a declarative system. You describe what data you want, how fresh it should be, and how errors or loading should be handled, and React Query takes care of the rest behind the scenes.

Think of each query as a contract.

You write:

  • “Here’s the data I need”
  • “Here’s how to get it”
  • “Here’s how I want to handle loading and errors”

And then React Query handles retries, caching, stale data, background updates, and more, without you writing any extra logic.

Why does this matter?

Simply because if you apply this style of thinking, it then lets you focus on your UI instead of wiring up fetch logic everywhere. The less you try to control every edge case manually, the more React Query can do its job.

The result is simpler code, fewer bugs, and a much smoother developer experience. In fact, if you embrace the declarative model fully, React Query almost disappears into the background, and that’s when it’s doing its best work!

Time to test this out in your projects

So as you can see, React Query removes the hassle of fetching data in React.

There’s no more juggling loading states, retries, or stale data. You just describe what you need, and it handles the rest cleanly, declaratively, and with almost no boilerplate.

Honestly, if your app talks to a server, this tool will make your life easier. You just need to give it a try to see what I mean.

And it doesn’t need to be a full rewrite. Start small. Replace one useEffect with useQuery, hook it up to a real API, and let it prove itself.

P.S.

Remember, if you want to learn more about React and how to use it, check out my complete React Developer course:

learn react

This is the only React JS bootcamp course you need to learn React, build advanced large-scale apps from scratch, and get hired as a React Developer in 2025.

Graduates from this program are now working at Google, Tesla, Amazon, Apple, IBM, Uber, Facebook, Shopify + other top tech companies. There’s no reason why you couldn’t do the same!

Plus, once you join, you'll have the opportunity to ask questions in our private Discord community from me, other students and other working tech professionals, as well as access to every other course in our library!


By the way, you can also check out all the ZTM courses available here.

More from Zero To Mastery

Best Places To Learn To Code In 2025 preview
Popular
Best Places To Learn To Code In 2025
36 min read

With 100's of sites to learn to code from online, which platform is the best for you? We got you. Here are the pros & cons for 14 of the best sites.

How To Ace The Coding Interview preview
How To Ace The Coding Interview
34 min read

Are you ready to apply for & land a coding job but not sure how? This coding interview guide will show you how it works, how to study, what to learn & more!

How To Learn Anything: Faster And More Efficiently preview
How To Learn Anything: Faster And More Efficiently
32 min read

Want to learn a new skill? Here are 19 tips, techniques, and tactics that you can use to learn (and remember) absolutely anything, today!