DEV Community

Cover image for Setting up React Query in your React project
Hugo Ramon Pereira
Hugo Ramon Pereira

Posted on

Setting up React Query in your React project

Introduction

Consuming data from an API or some sort of external source is always necessary throughout our applications and the traditional method using fetch API and the useEffect hook is a bit verbose, time-consuming and not advised. Axios emerged as a solution for that and currently, Axios is still dominant in use.

This is where React Query comes into play, React Query is responsible for managing asynchronous operations between server and client and it gives us many advantages.

So for this article, we will be talking about React Query v5 with Axios to provide an excellent combination of technologies, so that you can handle your requests, data fetching, asynchronous state handling, caching, garbage collection, memory management, refetching, loading states, react query dev tools and some examples.

Installation

npm i @tanstack/react-query
yarn add @tanstack/react-query
pnpm add @tanstack/react-query
Enter fullscreen mode Exit fullscreen mode

React-Query setup

After installation, the first thing we need to do in our React.js application is to wrap our entire application with QueryClientProvider and pass a client prop to it. Now React-Query is ready to be used.

import React from 'react';
import ReactDOM from 'react-dom/client';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';

const queryClient = new QueryClient();

export function App() {
  return (
    <QueryClientProvider client={queryClient}>
      <App />
    </QueryClientProvider>
  );
}
Enter fullscreen mode Exit fullscreen mode

We can also pass some initial properties to the Query Client:

Image description

React-Query DevTools - Optional

You can also install React-Query DevTools. React-Query Dev Tools will help you visualize data and everything that is going on and it is a tool that will give you important info to help you debug your application.

We have to install it since it is a separate package provided by Tanstack.

Here's how to install it:

npm i @tanstack/react-query-devtools
yarn add @tanstack/react-query-devtools
pnpm add @tanstack/react-query-devtools
Enter fullscreen mode Exit fullscreen mode

Now let's configure React-Query DevTools in our application, we can pass it inside the QueryClientProvider as a sibling of the main component . We can also pass 3 properties to define the position of the Icon that triggers the panel and the DevTools Panel itself.

  1. initialIsOpen - If you pass this then DevTools is going to be open by default
  2. position - The panel position, top, bottom, left or right
  3. buttonPosition - The position of the button that opens the panel, possible values are: top-left, top-right, bottom-left, bottom-right.
import React from 'react';
import ReactDOM from 'react-dom/client';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';

const queryClient = new QueryClient();

export function App() {
  return (
    <QueryClientProvider client={queryClient}>
      <App />
      <ReactQueryDevtools 
         initialIsOpen 
         position='right'     
         buttonPosition='bottom-right' 
      />
    </QueryClientProvider>
  );
}
Enter fullscreen mode Exit fullscreen mode

Image description

Implementation

With the initial configurations out of the way, we can now start using it for real.

The basics of React Query are 2 things, query and mutation. Query is when we fetch data from somewhere and mutation is when data is changed, this change can happen for several reasons, an update, data has become stale, a post, a put, patch request and React-Query will handle that for us.

To handle the requests to the API in this article we will be using Axios, to install it follow the steps:

npm i axios
yarn add axios
pnpm add axios
Enter fullscreen mode Exit fullscreen mode

I created an API configuration file to make requests to jsonplaceholder api to bring a list of the posts.

import axios from 'axios';

const todosApi = axios.create({
  baseURL: 'https://jsonplaceholder.typicode.com'
});

export async function getTodos () {
  const response = await todosApi.get('/todos');
  return response.data;
}

export async function addTodo (todo) {
  const response = await todosApi.post('/todos', todo);
  return response.data;
}

export async function editTodo (todo) {
  const response = await todosApi.patch(`/todos/${todo.id}`, todo);
  return response.data;
}

export async function removeTodo ({ id }) {
  const response = await todosApi.delete(`/todos/${id}`, id);
  return response.data;
}

export default todosApi;
Enter fullscreen mode Exit fullscreen mode

And I created a TodoList component where we will combine the code using Axios and React-Query.

import { useQuery, useQueryClient, useMutation } from '@tanstack/react-query';
import { getTodos, addTodo } from '../../api/api';

export default function TodoList() {
  const queryClient = useQueryClient();

  const { data, isLoading,  } = useQuery({
    queryKey: ['todos'],
    queryFn: getTodos
  });

  const { mutateAsync } = useMutation({
    mutationFn: addTodo,
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['todos'] });
    }
  });

  if (isLoading) {
    return <p>Loading posts...</p>;
  }
  return (
    <main>
      <h1>Todo List</h1>
      <ul>
        {data.map((todo) => (
          <li key={todo.id}>
            {todo.title}
          </li>
        ))}
      </ul>;

      <button onClick={() => {
        mutateAsync({
          id: Math.random(),
          title: 'Finish article'
        });
      }}>
        Add todo
      </button>
    </main>
  );
}
Enter fullscreen mode Exit fullscreen mode

If we weren't using React-Query we would have to create, loading states using useState, handle the errors, caching, as you can see in the image below:

Image description

As said before React-Query works with 2 concepts query and mutation and React-Query provides the hooks useQuery( ) and useMutation( ) for us to handle our asynchronous operations between Frontend and Backend.

The hook useQuery is used to fetch data and to do that we import those functions created in the API code previously provided. We are importing both code from React-Query and also the API that is using Axios.

When we use the hook useQuery( ) is common to pass an object with a queryKey which can be any name you want but it should be related to what sort of operation is being done to be more semantic, in our case we named it 'todos' because that is exactly what we are dealing with, we are fetching a list of todos. React-Query will handle cache, memory optimization, garbage collection and other things with this value.

We also pass a queryFn which is the function that will execute the request which in our case is being done by Axios.

const { data, isLoading } = useQuery({
    queryKey: ['todos'],
    queryFn: getTodos
});
Enter fullscreen mode Exit fullscreen mode

In the code above the getTodos function is in the api file and it was imported into this component to be used here with React-Query. And to have access to the posts fetched all we have to do is map through the data which is the first value destructured and now we have all the posts in a li tag.

<>
  <h1>Todo List</h1>
    <ul>
      {data.map((todo) => (
         <li key={todo.id}>
            {todo.title}
         </li>
      ))}
    </ul>;
</>
Enter fullscreen mode Exit fullscreen mode

We don't have to create states [isLoading, setIsLoading] because all of that and much more is already built-in and provided by React-Query.

if (isLoading) {
  return <p>Loading posts...</p>;
}
Enter fullscreen mode Exit fullscreen mode

As for the operations that will involve changes in the data, we will use the hook useMutation( ).

We can destructure many props from useMutation( ) and pass an object to it as in the useQuery( ) hook. But now we pass a mutationDn which is the function that will change data, it can be a request to the api or something.

We can also pass a callback function to onSuccess, onError to handle the success or error cases of the request.

const { mutateAsync } = useMutation({
    mutationFn: addTodo,
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['todos'] });
    }
});
Enter fullscreen mode Exit fullscreen mode

We can use the mutateAsync function that was destructured and use it in a button to be triggered via onClick( ) or something.

<button onClick={() => {
   mutateAsync({
      id: Math.random(),
      title: 'Finish article'
   });
}}>
Enter fullscreen mode Exit fullscreen mode

Conclusion
There are tons of other things that can be done with React-Query, we only scratched the surface here. To have more details and further info you can always turn to the official docs that will be provided below.

React-Query is a very powerful technology and you should use it in your projects along with Axios, you will have a powerful combination of tools to handle a lot of things that you would have to do by yourself, many useStates and useEffects can be avoided by using React-Query properly.

References
https://tanstack.com/query/v5/docs/react/overview

https://axios-http.com/

Top comments (0)