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 this 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 functions of the queryKey
and queryFn
as well as managing network request query states in React Query.
Top comments (0)