Using SWR hook with Suspense in React 18
Tags: javascript, webdev, react, frontend
Published: 2022-06-16 13:57:04

One of the reasons why I write these articles is to fortify the knowledge of new concept I recently learned, while trying to apply that knowledge to everyday tasks I have to do as a developer.
And one of the most common things you do as a developer is fetching some data from an API and present it on a client.

And I already wrote about that in the past, with "[Fetching data with React hooks and Axios](https://dev.to/darkmavis1980/fetching-data-with-react-hooks-and-axios-114h)" and just the other day I published "[A practical example of Suspense in React 18](https://dev.to/darkmavis1980/a-practical-example-of-suspense-in-react-18-3lln)" on the same topic.

But the latter article was using a very manual approach, where you write your wrapper around the fetching library to use the new `Suspense` component in React 18, but it's not the only way, and there's a new tool in the block that can make that same job way more simple and easy to use: [**SWR**](https://swr.vercel.app/).

## But what is SWR?

In the project own words:

> The name “SWR” is derived from stale-while-revalidate, a HTTP cache invalidation strategy popularized by [HTTP RFC 5861](https://datatracker.ietf.org/doc/html/rfc5861). SWR is a strategy to first return the data from cache (stale), then send the fetch request (revalidate), and finally come with the up-to-date data.

It's not a data fetching library for sure, it does the same job as the wrappers I talked [this previous article](https://dev.to/darkmavis1980/a-practical-example-of-suspense-in-react-18-3lln), and it let you use a simple hook to simplify the fetching process and how to handled it in a react functional component.

But on top of that it also cache it, so if you are requesting the same endpoint multiple times, it checks if the internal cache already the data you need (and if it's still valid), improving the overall performances of your application.

## Let's refactor our code

### Install the package

As usual, first thing to do is to install it, so:

```bash
npm install swr --save
```

### The starting point

So previously we had the following components and libraries:

- A wrapper for our fetching library that was throwing exception when the fetching promise was not resolved, so it was in a `pending` state, or it was rejected. 
[Example here](https://github.com/darkmavis1980/react-jest-boilerplate/blob/main/src/api/wrapPromise.js).
- A wrapped fetching logic, where we used `axios` to call an API to get our data, and it was wrapped by the function above. [Example here](https://github.com/darkmavis1980/react-jest-boilerplate/blob/main/src/api/fetchData.js)
- A child component that is calling the function to fetch the data and it renders the code with it.
- A parent component that uses Suspense with a fallback component, which it will be shown until the fetching promise is resolved, once that done, the child component will be rendered instead. [Example here](https://github.com/darkmavis1980/react-jest-boilerplate/blob/main/src/components/Home/Home.jsx).

### What we need to change?

So, the wrapper and wrapped function can go, we don't need that anymore.

The parent component will be unchanged, as everything will happen in the child component.

Our actual job will be to just refactor the child component, and the current code will look like this:

```javascript
import React from 'react';
import fetchData from '../../api/fetchData.js';

const resource = fetchData('/sample.json');

const Names = () => {
  const namesList = resource.read();

  return (
    <div>
      <h2>List of names</h2>
      <p>This component will use a custom handler for fetching data.</p>
      <ul>
        {namesList.map(item => (
          <li key={item.id}>
            {item.name}
          </li>))}
      </ul>
    </div>
  );
};

export default Names;
```

As we said, we can get rid of the old fetching logic, so this import line can be replaced with `swr` and `axios` import:

```javascript
// from this
import fetchData from '../../api/fetchData.js';

// to this
import useSWR from 'swr';
import axios from 'axios';
```

Now we still need to use `axios` to fetch our data, and this will replace our `resource` object we had before:

```javascript
// from this
const resource = fetchData('/sample.json');

// to this
const fetcher = url => axios.get(url).then(({data}) => data);
```

Here I'm using `axios`, but what library to use is up to you, you can use any fetching library you want as long it does return a promise with the data we want to read.

So far all of this is happening outside the component code, and while with the old logic we used to call a `read()` method from our `resource` object, like this:

```javascript
const Names = () => {
  const namesList = resource.read();
```

Now we need to use the `useSWR` hook instead, but there's a catch: in order to use the `suspense` component, you need to pass a parameter to tell SWR to support that:

```javascript
const Names = () => {
  const { data: namesList } = useSWR(
    '/sample.json',
    fetcher,
    { suspense: true}
  );
```

Some of you might wonder "Why I can just pass the url directly to the fetcher callback function?". The reason is because SWR will use that key as a cache key, so next time you will call that same endpoint, it will return the cached value.
And that's it! The rest of the code will be identical!
So the final children component code will look like this:

```javascript
import React from 'react';
import useSWR from 'swr';
import axios from 'axios';

const fetcher = url => axios.get(url).then(({data}) => data);

const Names = () => {
  const { data: namesList } = useSWR('/sample.json', fetcher, { suspense: true});

  return (
    <div>
      <h2>List of names with SWR</h2>
      <p>This component will use the SWR hook for fetching data.</p>
      <ul>
        {namesList.map(item => (
          <li key={item.id}>
            {item.name}
          </li>))}
      </ul>
    </div>
  );
};

export default Names;
```

The parent component will still be unchanged, as everything is happening in the children component, but in case you want to see how everything is wrapped with `Suspense`, here the code:

```javascript
import React, { Suspense } from 'react';
import Names from './Names';
import Loading from '../Loading';

const Home = () => (
  <div>
    <h1>Best devs:</h1>
    <Suspense fallback={<Loading />}>
      <Names />
    </Suspense>
  </div>
);

export default Home;
```

I hope this article helped you to understand how to use SWR with the new `Suspense` component in React 18 ;-)