Caching clash: useSWR() vs. react-query
Tags: react, javascript, webdev
Published: 2020-01-29 15:01:25

---
title: Caching clash: useSWR() vs. react-query
published: true
date: 2020-01-27 19:00:56 UTC
tags: react,javascript,webdev
canonical_url: https://blog.logrocket.com/caching-clash-useswr-vs-react-query/
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/be27l4545xgn0xh3x73g.jpeg
---
**Written by [Abdulazeez Abdulazeez Adeshina](https://blog.logrocket.com/author/abdulazeezadeshina/)**✏️

## Introduction

Storing data in our React application is mostly done through state. But what happens when the app is reloaded? The state returns to point blank, except it is filled up when the component mounts. This is usually done in the `useEffect()` Hook or `componentDidMount()` method.

The data loaded into the application’s state is mostly from an external source and repeatedly retrieved. But imagine a scenario in which the data source crashes for a moment or the network becomes slow, and as a result, our app returns a blank page without any data.

Luckily, there are two libraries that deal with the retrieval of data into cache without dealing with state: react-query and SWR. In this article, we will build a simple app to showcase the features of SWR and then compare SWR to react-query.

If you don’t what react-query is all about, [read on it here](https://dev.to/bnevilleoneill/using-suspense-with-react-query-3bcl). I’ll assume you are familiar with JavaScript, React, [React Suspense](https://dev.to/bnevilleoneill/the-future-of-react-unfolding-with-suspense-490g), and JSX. Lastly, all the code in this article can be found [here](https://github.com/Youngestdev/useswr-recipe-app).

[![LogRocket Free Trial Banner](https://i0.wp.com/blog.logrocket.com/wp-content/uploads/2017/03/f760c-1gpjapknnuyhu8esa3z0jga.png?resize=1200%2C280&ssl=1)](https://logrocket.com/signup/)

## SWR

[SWR](https://swr.now.sh/), an initialism derived from `stale-while-revalidate`, is a React Hook library from ZEIT that retrieves data from an external source (API), stores the data into cache, and then renders the data. This is similar to what react-query does. Some of the features of SWR we’ll be looking at include data fetching and Suspense mode.

The SWR library can be installed either from Yarn or npm:

```jsx
npm i swr

// or

yarn add swr
```

## What is `useSWR()`?

SWR’s `useSWR(key, fetcher, options)` is a Hook that retrieves data asynchronously from a URL with the aid of a fetcher function, both passed as arguments to the Hook. The key argument here is the URL in string format, and the fetcher is either a function declared in the global configuration, a predefined custom function, or a function defined as the `useSWR()` argument.

By default, `useSWR()` returns the data received, a validation request state, a manual revalidate argument, and an error, if there are any. This can be easily done by setting the Hook to a destructurable object variable:

```jsx
const { data, isValidating, revalidate, error } = useSWR(key, fetcher)
```

## `useSWR()` features

Data fetching is `useSWR()`’s primary feature. Just like react-query, data fetching is done once — only when the component is to render data — unlike the traditional method of loading data every time the component is rendered.

### Global configuration

`useSWR()` has a global configuration context provider that gives access to all the Hook’s options, so the options argument in the `useSWR()` Hook can be left blank. Here is an example of the global configuration in use:

```jsx
import useSWR, { SWRConfig } from 'swr'

function Example () {
  const { data } = useSWR('http://book-api.com')
  const { data: latest } = useSWR('http://latest-books-api.com')
}

function App () {
  return (
    <SWRConfig 
      value={{
        refreshInterval: 3000,
        fetcher: (...args) => fetch(...args).then(res => res.json())
      }}
    >
      <Example />
    </SWRConfig>
  )
}
```

In the code above, the global configuration provider component `<SWRConfig />` gives us the opportunity to define the fetcher function so we don’t have to add it as an argument every time in our `useSWR()` Hook. The fetcher defined in the global configuration provider is universal for the components consuming it, i.e., wrapped under it.

Although this isn’t a mandatory step when using the Hook, it is the best approach provided the app maintains data retrieval homogeneity.

### Fetching data

Fetching data with `useSWR()` is pretty straightforward. We’ll see from a little demo how data fetching works.

First, we define our sample component — let’s call it `RocketLauncher` — and store the result from our `useSWR()` into two destructurable variables:

```jsx
function RocketLauncher() {
  const { data, error }  = useSWR('http://rocket-time.api', fetcher)

  return  (
    <>

    </>
  )
}

const fetcher = url => fetch(url).then(r => r.json())
```

The destructurable variables contain the following:

1. The `data` variable holds the data returned from the `fetcher` function
2. The `error` variable holds whatever error is sent back from the Hook

Next, we render the data returned:

```jsx
...
<>
 { error ? (
      <b>There's an error: {error.message}</b>
    ) : data ? (
      <ul>
        {data.map(recipe => (
          <li key={rocket.id}>{rocket.name}</li>
        ))}
      </ul>
    ) : null }
</>
...
```

The block of code above renders the data retrieved from `u``seSWR()` if there’s no error returned; otherwise, a blank page is returned. We’ll get to see all these in action in the next section

## Building the app

In this section, we’ll be rebuilding a recipe app formerly built with react-query [in this article](https://dev.to/bnevilleoneill/using-suspense-with-react-query-3bcl) to demonstrate how `useSWR()` works. In the next section, we’ll take a look at the similarities and differences between the two.

Let’s get started.

### Setup

You can get the setup process for our application from the previous article linked above since we’re simply rebuilding the app with a different library.

### Components

The next thing we’ll do is build the app’s frontend. We’ll use the global configuration so we don’t have to call fetcher every time. We’ll also enable Suspense mode in the global configuration settings.

### `index.jsx`

```jsx
import React, { lazy } from "react";
import ReactDOM from "react-dom";

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement)
```

This is a basic render file. Next, we import `useSWR()` and the recipe components since we’ll be writing the main app component, `<App />`, in the `index.jsx` file:

```jsx
import useSWR, { SWRConfig } from "swr";
import fetcher from "./fetch";

const Recipes = lazy(() => import("./components/Recipes"));
const Recipe = lazy(() => import("./components/Recipe"));
```

We imported `useSWR` alongside the global configuration context provider. Next, we’ll write our `App` component:

```jsx
function App () {
  const [activeRecipe, setActiveRecipe] = React.useState(null);
  return (
    <React.Fragment>
      <h1>Fast Recipes</h1>
      <hr />
      <SWRConfig
        value={{
          refreshInterval: 3000,
          fetcher: fetcher,
          suspense: true
        }}
      >
        <React.Suspense fallback={<h1> Loading ...</h1>}>
          {activeRecipe ? (
            <Recipe
              activeRecipe={activeRecipe}
              setActiveRecipe={setActiveRecipe}
            />
          ) : (
            <Recipes setActiveRecipe={setActiveRecipe} />
          )}
        </React.Suspense>
      </SWRConfig>
    </React.Fragment>
  );
}
```

In the code above, we wrap our lazily loaded recipe components under React’s Suspense, which is also wrapped under the global configuration provider, `SWRConfig`.

The global configuration provider has been equipped with our fetcher function, which we will define next, so we don’t have to add the fetcher as an argument to the `useSWR()` Hook in the `Recipe` and `Recipes` components.

### `fetch.js`

This file contains the code that retrieves data from the source passed into the `useSWR()` Hook in JSON format.

```jsx
import fetch from "unfetch"

const fetcher = url => fetch(url).then(r => r.json())

export default fetcher;
```

### `Recipe.jsx`

We’ll start off by importing React and the SWR library:

```jsx
import React from "react";
import useSWR from "swr";

import Button from "./Button";
```

Next, we’ll write the `Recipe` component:

```jsx
export default function Recipe({ activeRecipe, setActiveRecipe }) {
  const { data } = useSWR(
    "http://localhost:8081/" + activeRecipe);
  return (
    <React.Fragment>
      <Button onClick={() => setActiveRecipe(null)}>Back</Button>
      <h2>ID: {activeRecipe}</h2>
      {data ? (
        <div>
          <p>Title: {data.title}</p>
          <p>Content: {data.content}</p>
        </div>
      ) : null}
      <br />
      <br />
    </React.Fragment>
  );
}
```

The `Recipe` component takes two props, `activeRecipe` and `setActiveRecipe`, that are involved with the retrieval and rendering of data.

The `useSWR()` Hook is passed the data source URL and the data to be retrieved is stored in the data variable. The data upon retrieved is retrieved is rendered as can be seen from lines 8 to 13. The data returned is cached and won’t be retrieved when the app loads again unless there is a change in the data from the source.

> It follows a mechanism of “if retrieved data is the same as what’s in the cache, render cache data; otherwise, cache the new data.”

We’ll write the `Recipes` component next.

### `Recipes.jsx`

The `Recipes` component is responsible for the rendering of the list of recipes retrieved from the data source via `useSWR()`. The code responsible for that is:

```jsx
import React from "react";
import useSWR from "swr";
import Button from "./Button";

export default function Recipes({ setActiveRecipe }) {
  const { data: Recipes } = useSWR(`http://localhost:8081`);
  return (
    <div>
      <h2>
        Recipes List        
      </h2>
      {Recipes ? Recipes.map(Recipe => (
        <p key={Recipe.title}>
          {Recipe.title}
          <Button
            onClick={() => {
              setActiveRecipe(Recipe.id);
            }}
          >
            Load Recipe
          </Button>{" "}
        </p>
      )) : 'loading'}
    </div>
  );
}
```

In the component, we started off by importing React and SWR to enable us to use the `useSWR()` Hook.

A loading message is displayed when the data is being fetched. The `useSWR()` Hook is used to retrieve the list of recipes from the backend.

Next, the data retrieved from SWR is cached, mapped out from its array, and then rendered on the DOM, as can be seen from lines 12 to 23.

The code for the helper component `Button` follows below.

### `Button.jsx`

```jsx
import React from "react";
export default function Button({ children, timeoutMs = 3000, onClick }) {
  const handleClick = e => {
      onClick(e);
  };
  return (
    <>
      <button onClick={handleClick}>
        {children}
      </button>
    </>
  );
}
```

## Running our app

Next thing is to preview the app we’ve been building. We’ll start by running the app first without the backend to verify that a blank page will be displayed when no data is returned. From your terminal, start the React app and the backend in two different terminal consoles:

```jsx
//React App
npm run start or yarn start

//Backend App
node api.js
```

Next, open the app on your browser with [`http://localhost:3000`](http://localhost:3000/) and you should get the same page as the one in the gif below. Feel free to check the recipes one after the other, and reload the app to experience caching.

![useSWR Recipes App](https://i0.wp.com/blog.logrocket.com/wp-content/uploads/2020/01/useswr-recipes-app-preview.gif?resize=730%2C443&ssl=1)

## SWR vs. react-query

If you have followed the two articles, you will have noticed that they both perform the same functions: rendering, fetching data, and caching. However, in addition to those basic similarities, there are some differences between the two libraries.

### Similarities

#### Fetching and caching data

Both react-query and SWR are Hook libraries that fetch data remotely. These two libraries fetch data asynchronously and caches data upon retrieval and a result, prevents the continuous retrieval of data from the data source on every app render.

#### Suspense mode

Both libraries allow the use of React’s suspense. This feature allows the app to keep the user updated while the app fetches data via either of the libraries.

#### Fast and reactive app state

Both libraries improve the load time and responsiveness of your app, especially when rendering data after the first time. This is due to the caching of data, which makes it readily available whenever the app needs it (even when it’s offline).

That said, there is a small difference in load time between `useSWR()` and react-query. `useSWR()` comes out on top here, 628ms to 523ms, as shown in the screencaps below.

![useSWR Load Time](https://i1.wp.com/blog.logrocket.com/wp-content/uploads/2020/01/useswr-load-time.png?resize=730%2C130&ssl=1)<figcaption id="caption-attachment-13111">useSWR() load time.</figcaption>

![React-query Load Time](https://i0.wp.com/blog.logrocket.com/wp-content/uploads/2020/01/react-query-load-time.png?resize=730%2C130&ssl=1)<figcaption id="caption-attachment-13112">react-query load time.</figcaption>

### Differences

Although both applications are remote, data fetching, agnostic Hook libraries, they have their differences — they are written by different authors, after all. These libraries have limitations and advantages over each other. Let’s take a look at them.

#### Global fetcher

Unlike react-query, where we have to call the fetcher as the second argument, SWR enables us to define a global fetcher function in the configuration provider so we don’t have to import or define the fetcher function every time we need to use the `useSWR()` Hook.

#### Prefetching data

React-query has an advantage over SWR in this regard. SWR is capable of prefetching data, but it requires additional configurations, such as writing more functions and mutating them to the `useEffect()` Hook. In contrast, react-query has a prop handler that lets you prefetch data by setting the data ID and source without extra configurations.

#### GraphQL support

SWR offers greater advantage for modern apps that use GraphQL. It is often said that REST may soon be laid to rest, and indeed, GraphQL is a much faster and more efficient alternative to REST.

In REST, you have to query the whole API to get specific data and results, which returns a whole lot of (mostly unused) data, slowing down your app. GraphQL, on the other hand, allows you to retrieve only the data you need [by specifying it in the query](https://dev.to/bnevilleoneill/graphql-queries-explained-in-simple-terms-4inc), thereby returning only a little response data.

GraphQL queries can be sent and data received, as demonstrated in this snippet from the SWR library:

```jsx
import { request } from 'graphql-request'

const API = 'https://api.graph.cool/simple/v1/movies'
const fetcher = query => request(API, query)

function App () {
  const { data, error } = useSWR(
    `{
      Movie(title: "Inception") {
        releaseDate
        actors {
          name
        }
      }
    }`,
    fetcher
  )
  // ...
}
```

#### Mutating data

SWR enables update data locally while waiting for the remote source to revalidate it.

## Conclusion

Both libraries are great for remote data fetching and can be used in React projects. SWR generally works hand in hand with Next.js, another project from the authors.

However, SWR has the major advantage due to its compatibility with GraphQL and overall speed, as these are some of the factors taken into consideration when selecting third-party libraries for (mostly large-scale) applications.

Therefore, for large-scale applications or projects that have to do with the distribution of data, SWR is preferred, while react-query is better for side projects or smaller applications.

In this article, we looked at what SWR is, the `useSWR()` Hook, and its features by rebuilding a recipe app previously built with react-query. We also looked at the similarities and the differences between SWR and react-query.

Lastly, you can read more on [SWR](https://github.com/zeit/swr) and [react-query](https://github.com/tannerlinsley/react-query), and you can see the full code for the app we built in [this GitHub repo](https://github.com/Youngestdev/useswr-recipe-app). Happy coding.❤

* * * 
## Full visibility into production React apps 

Debugging React applications can be difficult, especially when users experience issues that are difficult to reproduce. If you’re interested in monitoring and tracking Redux state, automatically surfacing JavaScript errors, and tracking slow network requests and component load time, [try LogRocket.](https://www2.logrocket.com/react-performance-monitoring)

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/eq752g8qhbffxt3hp9t4.png)

[LogRocket](https://www2.logrocket.com/react-performance-monitoring) is like a DVR for web apps, recording literally everything that happens on your React app. Instead of guessing why problems happen, you can aggregate and report on what state your application was in when an issue occurred. LogRocket also monitors your app's performance, reporting with metrics like client CPU load, client memory usage, and more.

The LogRocket Redux middleware package adds an extra layer of visibility into your user sessions. LogRocket logs all actions and state from your Redux stores.

Modernize how you debug your React apps — [start monitoring for free.](https://www2.logrocket.com/react-performance-monitoring)
* * *

The post [Caching clash: useSWR() vs. react-query](https://blog.logrocket.com/caching-clash-useswr-vs-react-query/) appeared first on [LogRocket Blog](https://blog.logrocket.com).