What is React Query?

Luciana Moll
Leniolabs_
Published in
4 min readJul 15, 2020

React-Query is a library that allows you to make requests and handle response metadata. To make a query, define a unique key and an asynchronous function to resolve data, as parameters of useQuery.

Basic implementation:

import { useQuery } from ‘react-query’function App() {
const info = useQuery(‘todos’, fetchTodoList)
}

In this case, todos is the unique key, and fetchTodoList is the async function.

Complex implementation:

function Todos() {
const { isLoading, isError, data, error } = useQuery("todos", fetchTodoList);
if (isLoading) {
return <span>Loading...</span>;
}
if (isError) {
return <span>Error: {error.message}</span>;
}
// also status === 'success', but "else" logic works, too
return (
<ul>
{data.map((todo) => (
<li key={todo.id}>{todo.title}</li>
))}
</ul>
);
}

If you prefer to avoid booleans to handle the different states, a status variable is provided by the library:

function Todos() {
const { status, data, error } = useQuery('todos', fetchTodoList)
if (status === ‘loading’) {
return <span>Loading...</span>
}
if (status === ‘error’) {
return <span>Error: {error.message}</span>
}
// also status === 'success', but "else" logic works, too
return (
<ul>
{data.map(todo => (
<li key={todo.id}>{todo.title}</li>
))}
</ul>
)
}

As we can see, it’s very simple to implement and we can handle which element renders depending on the status.

React-query vs custom hook

Suppose we have a custom hook called useFetch:

import { useState, useEffect } from "react";const useFetch = (url, options) => {
const [response, setResponse] = useState(null);
const [error, setError] = useState(null);
const [isLoading, setIsLoading] = useState(false);
useEffect(() => {
const fetchData = async () => {
setIsLoading(true);
try {
const res = await fetch(url, options);
const json = await res.json();
setResponse(json);
setIsLoading(false);
} catch (error) {
setError(error);
}
};
fetchData();
}, []);
return { response, error, isLoading };
};

This is already quite complex, and we did not even start to account for caching, invalidation and other features. The benefits of react-query library are:

  • Avoid so many lines of code and complexity.
  • It allows you to have queries ordered and set different parameters to each one.
  • When the data becomes obsolete, it does a refetch in the background or you can do a manual refetch (explained in the next section)
  • It makes it easier for you to obtain the status and if isLoading, isError, etc.
  • Provides an easier way to load-more, infinite scroll, dependent queries, paging, caching, and many more.

The list of benefits is extensive, and it can be extended further if we decide to explore the library more. Let’s go one step further to usages.

Usages

If we explore the documentation of the library, we can see a lot of parameters that can be set up to do many things. From making parallel, paginated, dependent, load-more and infinite scroll queries, to caching them.

I want to highlight something very important here, query results (via useQuery and similar hooks) will become “stale” immediately after they are resolved and will be refetched automatically in the background when they are rendered or used again.

There are 2 ways to change this behavior. One way, you can alter the default staleTime for queries to something other than 0 milliseconds. Another way is using the third param of useQuery to set “manual” in true. Besides that, we can use refetch to call when you want and update data. It could be depending on a variable or maybe in a callback.

Example 1:

const {
status: randomStatus,
data: randomData,
refetch: refetchRandom,
} = useQuery("randomCharacter", getCharacterRandom, { manual: true });

Example 2:

const { status: allStatus, data: allData, refetch: refetchSearch } = useQuery(
"characters",
() => getCharacters(characterSearch),
{
manual: true,
}
);

Other important things are:

If we have to implement multiple queries, we can rename the params that useQuery returns. On example 1, function doesn’t have parameters, but as we see on example 2, the async function needs one. If we only do this: getCharacters(characterSearch), we are executing the function. That’s why we resolved implementing it with an arrow function.

There are many ways to optimize and options to set up react-query depending what you want to do. Explore this fantastic and useful library.

Should we replace the traditional custom hook to handle the response?

I think we can replace the traditional custom hook to make requests without using useState and useEffect, with many lines of code to return data in a success response, isLoading while is requesting, or error in that case. We could have a Hooks folder, in which we could have many files depending on the topic or setting of the queries. I also believe that react-query gives you the freedom to implement your queries in a way that fits your application architecture.

--

--

Luciana Moll
Leniolabs_

Software Engineer, Front-end Developer at Leniolabs