Restore your faith in server-state data synchronization with the pre-configured React Query library. See how you can bring fetch, cache, and update logic to a few understandable lines of code with simple automation hooks presented in this tutorial.

Why is it the next big thing?

It was React’s missing piece that helps with server-state data management. Forget about keeping everything in a standard global state, because most libraries were created to handle client state only and the server state is way different. 

Server data is asynchronous. As it’s not stored in your app, it can go out of date in a blink, so you should figure out a way for building cache. Here’s the bad news — it’s one of the hardest things in programming. But the good news is that React Query can handle your fetching, caching, synchronizing, and updating the server state.

Why is it cool to start a project with React Query?

One-liner time — it will take your app to a new level. But really, consider the examples below.

Key benefits of React Query

  • Window focus refetching – when a user leaves your app tab, React Query marks the data “stale” and refetches it when that person returns.
  • Request retry – you can set an amount of retries for any request to combat random errors.
  • Prefetching – if your app needs fresh data after an update request, you can prefetch the query with a specific key, and React Query will update it in the background.
  • Optimistic Updates – when you edit or delete an item in a list, you can issue an optimistic update of the list.

Starting the React Query engine

Here’s the basic configuration.

Let’s assume we have a basic axios function which returns data for our articles.

Fetching that data with the help of React Query is really simple.

Fetching is now better

Why is it better than common fetching with the useEffect pattern? When you use that query with the same projects key, React Query first returns previously fetched data, and then it fetches it again.

When the second data set is the same as the first set, React Query keeps both as a reference without forcing a reload. That’s a tremendous improvement to UX work.

How update hooks work

So you know how to fetch data easier. Let’s see how to update it.

React Query has the useMutation hook you can use to update/create/delete data. useMutation gives you access to the mutate function to which we can pass necessary arguments. it then returns information about the status of our API call. The status can be:

  • idle for an idle or fresh/reset state
  • loading for a mutation that is currently running
  • error when we encountered one
  • success when everything was ok and our data is available

You can access the status information from the status variable or, for those who prefer boolean states , they’re accessible through the following variables.

  • isIdle
  • isLoading
  • isError
  • isSuccess

As you see, it’s super easy to use. As there are more options you can pass to useMutation, React Query can become one of your most powerful developer tools.

Here is the real power

What happens when a device goes offline for a moment while sending data? React Query has a solution for that!

Use Request Retry

You can pass the retry option with the number of times the Query should retry the mutation after reconnection.

Query Client helps a lot with caching

The function packs in a lot of methods you can use to handle cache.

  • invalidateQueries method marks a query with a given key as invalid to make React Query fetch that data again. You can use that method in useMutation hook after a successful update (example below).
  • setQueryData, used for optimistic updates of the query’s cached data.
  • prefetchQuery method can help you to prefetch some data before it’s needed and rendered with useQuery. If you know when the user needs that particular data, use that method to fetch it earlier to improve UX.
  • clear simply clears all connected caches.

To use these methods, import the useQueryClient hook from the React Query library. Then, assign it to the const queryClient = useQueryClient() variable, and call your method on that variable with queryClient.invalidateQueries().

useMutation hook options

In most cases, you will use the Query Client methods inside of hooks options. Let’s look at the latter now.

  • onMutate function fires before useMutation. It’s quite helpful when you want to run optimistic updates on local cache and update data for the UI before the mutation happens on the server.
  • onSuccess function’s code runs when the mutation is successful. Queries with key articles get refetched in the background. Let’s see that in an example below.
  • onError fires when the mutation encounters an error, and it takes the context as one of arguments. It’s very common to set cache to previous data when something goes awry.

Other hot functionalities

Parallel queries

React query’s useQueries hook lets you execute many queries simultaneously to maximize fetching concurrency. It accepts an array of queries options objects like the useQuery hook to return an array of query results.

Dependent queries

They’re useful when you want to use data returned from one query to execute another one. Do that with the enabled option in useQuery.

Paginated queries

This is a very common concept that every developer uses daily. Just nod your head, please. And finally, React Query can help you use them better! 

You just need to pass the page number to the queryKey array and use the keepPreviousData option in the useQuery hook. Afterward, when you jump between pages, you get cache data from the first one with new data loading in the background. The UI won’t reload when the data is the same as before.

Optimistic updates

So what’s that optimistic update? Is it positive :)? Let’s say you have a simple star rating system in an article. 

With optimistic updates implemented, when you give the article a star, the UI accepts the command immediately without waiting for a server response. The code ensures the system will run an optimistic update before performing a mutation. Here is an example from React Query’s documentation.

Data handling done smarter

React Query really helps us nail the problems with asynchronous data handling. Life used to be harder. Developers needed a bunch of other libraries, and they’d end up putting the server data into a global store. Not a great idea. Why? As I mentioned earlier, keeping asynchronous server data in a global store adds unnecessary complexity to our code.

There’s more. The Query also helps to reduce the amount of boilerplate code (such as keeping every fetch in useEffect hook). When used well, it will revamp the user experience BUT it can also break it. So be careful and try to get to know this library first.

Leave a Reply