Caching made easy with React Query

It is that simple to manage server state.

Daniel Afonso
May 8 · 5 min read

Hey everyone, I’m making this post to share with you a library that made managing server state on React applications easy and fun — React Query.

In this blog post, I’ll do a small introduction by explaining what led to its creation followed by an introduction to how the useQuery hook works. I’ll end this post by showing some custom configurations we can do, and how we can do cache invalidation, data refetching, and optimistic updates.

Until now, many React applications have been relying on global state as a way to share data between components and avoid prop drilling.

Despite this apparent advantage, global data is often poorly used, and often is used without thinking if what we are adding there should be global to our application. Another thing that often happens is mixing server state with the client state. So what is the difference between client state and server state?

Client State

This is the type of state that is owned by our application. This state is temporary, local, and generally non-persistent between sessions. It is accessed with synchronous APIs that don’t have any latency. This state is more reliable, as it is generally always up to date.

Server State

This state is persisted remotely, which means that we may share ownership of it with other applications. It is asynchronous, so this means we’ll need to access it using asynchronous APIs. Due to these circumstances, this means that we have no guarantees that this state is up to date on our application.

By making our global state a mix between server and client state, we may end up making tradeoffs that would favor one type of state when compared with the other.

Server State has very specific challenges we don’t face with client state. These challenges are things like caching, background updates, deduping requests, dealing with outdated requests, and others.

To deal with these challenges and to break up our server state from our client one, React Query was created.

What is React Query?

React Query is a collection of hooks for fetching, caching, and updating asynchronous state in React. It’s a simple and small API that can be used out of the box with zero configuration.

It is protocol agnostic, so this means we can use REST, GraphQL, or whatever the use case is, and it supports things like auto caching and refetching out of the box.

Caching

The great thing about React Query is that the caching is done “behind the scenes” and we need minimal worries about it.

Let’s see the useQueryhook.

useQuery usage

Every call to the useQuery must be done with a unique key and with a function for resolving the data.

The key must respect the following types:

String | [String, Variables: Object] | falsy | Function => queryKey

There are some considerations for this query key:

  • It should be unique as it will be used internally for refetching, caching, and deduping related queries.
  • Internally it will be turned into an array. So if you only provide a string it will be turned into [‘key’] internally.
  • They are serialized deterministically. This means that order is irrelevant in cases that we use [‘key’, {page, status}] as a key.
  • The key is passed as parameters to the query function in the order they appear on the key array.
  • If a falsy value is passed as part as the query key then the query function won’t be called. This is great in cases we want to do serial queries (when we need data from a query to execute the next one).

The query function must respect the following:

Function(variables) => Promise(data/error)

This last part is exciting because it means you can use fetch, axios, or whatever you have on your application, as long as it resolves the data you need.

Some caching considerations

  • Rendered query results will become stale after they are resolved. This means that they will be refetched automatically on every rerender. To avoid this, we should specify the staleTime property.
  • Stale queries will be refetched when the browser window is refocused by the user. To avoid this, we should alter the refetchOnWindowFocus property.

Cache invalidation, Data refetching, and Optimistic Updates

In cases, we need to perform server side-effects like create/update/delete data we have the useMutation hook. This hook is really useful in case we want to data refetching due to some POST for instances.

We can make use of its onSuccess option to access the queryCache object and perform some query refetching and current cache invalidation. This can be seen in the following example

on addBlogPost mutation success refetch all queries that have “posts” as key.

If we want, we can also leverage the onMutate option and perform optimistic updates. This will allow us to update our UI before the mutation happens on the server-side, so it must be used with care as if the mutation fails, we may end up displaying out-of-sync data to our users. To avoid this last use case, we can perform a rollback of our changes.

When an optimistic update is performed, a reference to the previousPosts is returned in case we have to rollback onError.

Configurations

If you see yourself often defining the staleTime property or any other property, you can make use of the ReactQueryConfigProvider to wrap your App and set the defaults that will be used by React Query hooks.

Setting some defaults using the ReactQueryConfigProvider

Conclusion

As you can see, managing server state is so much simpler using React Query.

If you want to learn more, I invite you to read the official docs and to watch Tanner Linsley talk at React Summit where he introduces React Query and shows a more hands-on example.

I hope you enjoyed and stay tuned for the next ones.

Have a nice weekend and until next time!

A note from the Plain English team

Did you know that we have four publications? Show some love by giving them a follow: JavaScript in Plain English, AI in Plain English, UX in Plain English, Python in Plain English — thank you and keep learning!

Also, we’re always interested in helping to promote good content. If you have an article that you would like to submit to any of our publications, send an email to submissions@plainenglish.io with your Medium username and what you are interested in writing about and we will get back to you!

JavaScript In Plain English

New articles every day.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store