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:
idlefor an idle or fresh/reset state
loadingfor a mutation that is currently running
errorwhen we encountered one
successwhen 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.
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.
invalidateQueriesmethod 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.
prefetchQuerymethod 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.
clearsimply 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
useMutation hook options
In most cases, you will use the Query Client methods inside of hooks options. Let’s look at the latter now.
onMutatefunction 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.
onSuccessfunction’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.
onErrorfires 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
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.
They’re useful when you want to use data returned from one query to execute another one. Do that with the
enabled option in
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.
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.