Introduction to TanStack Query: Supercharge Your Data Fetching in a React App

Introduction to TanStack Query: Supercharge Your Data Fetching in a React App

Introduction

The process of fetching data into a web application is an essential part of the development of web applications.

In this guide, you’ll learn how to fetch data into your React app and manage network request states with TanStack Query. React lets you fetch data flexibly. You can fetch data in the useEffect hook and manage the state with useState.

While this works fine for your basic data fetching needs, it works well for client state management. However, when you need to manage your application server state React hooks do not do the job well enough.

There are several ways to fetch data in a React app. This guide shows you what TanStack Query is, and how to get started with using it alongside a demo API (Application Programming Interface) to get a hands-on experience.

You will fetch data from the JSON Placeholder API users endpoint, handle the network requests states with TanStack Query, and also show the returned data on the User Interface (UI).

Prerequisite

Before you go ahead with this technical write-up, it is important that you already have some understanding of JavaScript and React. Ideally, to get the most out of this lesson you should have an understanding of JS functions, React components, and hooks.

What is Data Fetching?

When you look up the meaning of data in the Oxford Dictionary, data is defined as “facts or information, especially when examined and used to find out things or to make decisions”.

From the definition above you can see that data is what you as a developer would work with. Based on the peculiarity of your project, the way you present the data is thus important to help the consumers make an informed decision or find out things.

Data fetching is the process of retrieving information from a data source. Examples of data sources are a database storage system, an Application Programming Interface (API), or a headless Content Management System (CMS).

Concept of Data Fetching in a React App

You can fetch data into your React web app from a database, API, or headless CMS. To fetch data into your React web app, use the Fetch API tool built into most modern web browsers or third-party libraries like Axios and ky fetch.

Fetching data is a side effect in React, you'll need to do it inside the useEffect hook. There are some gotchas with this approach, especially when you are fetching asynchronous data. You have to manage the states yourself. This is not robust enough, so there are some third-party libraries you can use to fetch data instead of fetching the data inside the useEffect hook.

Data Fetching Tools

There are several third-party libraries you can use to handle data fetching in your React web app. Here are two third-party libraries that are quite popular:

  • TanStack Query (React Query)

  • State While Revalidate (SWR)

What is TanStack Query?

TanStack Query is a powerful server state management library for React, Vue, Svelte, and JavaScript. This means that you can use TanStack Query for any of the JavaScript frameworks/libraries.

With useEffect and useState hooks, you can fetch your data and manage the network request state. However, handling stuff like caching, and revalidating stale data requires a lot more work with this approach.

TanStack Query helps you to write your fetching logic in a declarative way. In addition to data fetching and state management, it also accommodates caching, stale data revalidation, and optimistic updates with little to no configuration.

Originally known as React Query, TanStack Query is now available in other JavaScript frameworks/libraries with recent updates, and you will learn the React version of TanStack Query in this tutorial.

Features of TanStack Query

Using TanStack Query has a lot of benefits because of the features it has out of the box. Below is a highlight of some of the features it offers:

  • Prefetching data

  • Caching

  • Revalidating stale data

  • Pagination

  • Data mutations

How TanStack Query helps with state management, synchronization, caching, and error handling

It is quite important to note that TanStack Query does not do the data fetching for you as some would think.

Rather it’s more like a data fetching management tool, which means that you still have to fetch the data using either the browser-supported Fetch API, Axios, or Ky fetch. While TanStack Query takes it up from there and manages the server state with a queryKey and queryFn.

TanStack Query is available globally, so you don’t have to make network requests often. The queryKey is used to serve cached data which can still be used while revalidated data is fetched. This is similar to the Next JS Stale While Revalidate (SWR) data fetching library.

Remember you still have to fetch the data into your React app using either Fetch API or any of the third-party libraries. The data fetching function is often an asynchronous function that you have to pass to the queryFn. You will see all this in a demonstration shortly.

TanStack Query offers the different states of network requests like isLoading, isError, success, and the data itself out of the box to use without using the useState hook to handle it.

Installing TanStack Query in a React App

To set up TanStack Query, you need to create a React app.

Proceed to create a React app using Vite. Run this command in your command line tool:

NPM

npm create vite@latest

Yarn

yarn create vite

Install TanStack Query

You can install TanStack Query in your React App with NPM or Yarn.

Ensure to install the react version as shown below.

NPM

npm i @tanstack/react-query

Yarn

yarn add @tanstack/react-query

Using TanStack Query

Import TanStack Query

When using TanStack Query, you need to import it and make it available globally in your React app. To achieve this, import it at the top level of your React app which is inside the main.jsx file in the src folder.

To get started with this, the first line of action you need to carry out is to create a provider, which is QueryClientProvider component. The QueryClientProvider component wraps your entire app. The QueryClientProvider provides and connects QueryClient to your application.

You may be asking, what then is a QueryClient?

QueryClient is a class from the TanStack query library that is used to fetch and cache a query. To use QueryClient, you pass it as a prop to <QueryClientProvider> .

Here is how your main.jsx file should look like:

import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App.jsx';
// import QueryClientProvider and QueryClient from tanstack/react-query
import { QueryClientProvider, QueryClient } from '@tanstack/react-query';
import './index.css';

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

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

Fetching Data

For a quick walkthrough of how you can get started with using TanStack Query in your React app. You’ll make a fetch request to JSON Placeholder to fetch users.

useQuery Hook

The useQuery hook grants you access to your data in the FetchUsers component without the need for a useState and useEffect hooks to fetch your data.

Also, you get access to other network request query states such as isLoading, error, isFetching, status, and a whole bunch of other states. See the official docs to read more on useQuery.

Proceed to create a component folder inside the src folder, inside the component folder, create a FetchUser.jsx component.

Import the FetchUsers.jsx component inside the App.jsx file:

import FetchUsers from './components/react-query/FetchUsers';

function App() {
  return (
    <div>
      <FetchUsers />
    </div>
  );
}

export default App;
// import useQuery from tanstack
import { useQuery } from '@tanstack/react-query';

// Fetch users from JSON Placeholder using the Fetch API
async function fetcher() {
  const response = await fetch('https://jsonplaceholder.typicode.com/users');

  if (!response.ok) {
    const message = `An error has occured: ${response.status}`;
    throw new Error(message);
  }

  const json = await response.json();

  return json;
}

function FetchUsers() {
  const {
    data: users,
  } = useQuery({
    queryKey: ['users'],
    queryFn: fetchUser,
  });

  return (
    <div>
      {users?.map((user) => (
        <li key={user.id}>{user.username}</li>
      ))}
    </div>
  );
}

Here is an explanation of what the code above does:

To fetch data using react-query, you have to first import the useQuery hook which is a custom hook in react-query. You proceed to fetch the data; in this example, you'll be using JSON Placeholder (https://jsonplaceholder.typicode.com/users) endpoint and the browser Fetch API.

Also, if you noticed that data is annotated with the word user. This is a common pattern instead of using the general word data to make it easier to read and debug.

Note that your data can be anything.

Inside the FetchUsers react component, you call the useQuery hook and pass it an object. Inside the object, you have the queryKey and queryFn.

queryKey

When you make a network request for the first time. React Query caches the data internally with the queryKey. On subsequent network requests, React Query checks if the data is cached, if it is, React Query serves the cached data instead of making another network request.

The queryKey is also used for prefetching data when the dependencies change. A good example is when you add or delete from the list of users, the queryKey updates the query.

Another use of queryKey is to ensure that users are getting an updated UI by invalidating cached data to show updated data.

It is important to note that the queryKey is usually an array, and you can pass more than one item to the array.

queryFn

The second part, which is queryFn is your data fetching function which is often an asynchronous function.

From the sample code, you can see that the fetcher function is passed to the queryFn by reference. You can also make your fetch request inside the useQuery hook. However, this approach makes the code easier to read.

Loading and Error State

To indicate the status of the query when using Tanstack Query, the isLoading and isError states are used.

The isLoading state is set to true when the query is in progress but there is not yet any data available.

The isError state is set to true when an error occurs during the query. While the query is being executed, these states can display a loading spinner or an error message to the user

Back to the code, to add the isLoading, isError, and error state status, you'll add them to the useQuery hook.

Here is the code sample:

// Add isLoading, isError, and error state to useQuery hook inside the FetchUser component
...
const {
    isLoading,
    isError,
    error,
    data: users,
  } = useQuery({
    queryKey: ['users'],
    queryFn: fetchUser,
  });

// Loading state
if (isLoading) return <p>Loading...</p>;

// Error state
if (isError) return <p>Error: {error.message}</p>;
...

To see the loading and error state in action, carry out the following steps:

Loading State

Open your browser console by pressing:

  • Control + Shift + I on Windows
  • Command + Option + I on Mac

  • Go to the Network tab, and change it from No Throttling to Slow 3G.

  • Realod the page, you'll see the Loading... paragraph text.

Error State

To simulate an error, you can provide an invalid URL (https://xjsonplaceholder.typicode.com/users).

// Invalidating the URL
async function fetchUser() {
  const response = await fetch('https://xjsonplaceholder.typicode.com/users');
}

You should see the error message: Error: Failed to fetch

In comparison to using the useEffect and useState hooks to fetch and manage data in React, this approach is straightforward and easier to maintain.

Conclusion

In this guide, you learned how to use TanStack Query (React Query) to fetch data and manage state and why it is a better alternative to the useEffect and useState hooks in React.

You learned how to set up React Query in your React and make it globally available by wrapping your React app with the QueryClientProvider. You created a QueryClient class and passed it as a prop to QueryClientProvider.

A FetchUsers component was created and, you learned how to use the useQuery hook. The function of the queryKey and queryFn as well as managing network request query states in React Query.