How to Use SWR for Better Data Fetching Approach
Tags: react, webdev, javascript, programming
Published: 2023-05-22 04:51:30

In React, external data is very important to make your project more dynamic. However, when you use `useEffect` for data fetching, it is generally hard to manage the state, fortunately SWR simplifies this process.

## Introduction to SWR

The first thing I want to say is what SWR means.

According to its documentation:

> The name “SWR” is derived from `stale-while-revalidate`, a HTTP cache invalidation strategy popularized by [HTTP RFC 5861](https://tools.ietf.org/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.

**So, SWR is a library that provides React hooks for data fetching.**

## Implementing SWR in Your Project: My Experience

I recently completed the first project for the [Front End Libraries Certification](https://www.freecodecamp.org/learn/front-end-development-libraries) of FreeCodeCamp. I tried SWR in this project and will share my experience.

**Note:** For more information, you can check the project's [GitHub repository](https://github.com/femincan/quote-factory) and [CodeSandbox](https://codesandbox.io/p/github/femincan/quote-factory/main).

**I used TypeScript for this project, but I will give you examples with JavaScript. So, don't worry if you don't know TypeScript. (I highly recommend it if you don't know.)**

### 1\. Creating `fetcher` function

I was planning to use Axios for the requests, so I created the async function below.

```javascript
const fetcher = async (url) => {
  const { data } = await axios.get(url);

  return data;
};
```

This function is just a wrapper for the `get` method of Axios. It accepts a `url` parameter and returns `data`.

### 2\. Creating a hook that fetches a random quote

Based on the section [**Make It Reusable**](https://swr.vercel.app/docs/getting-started#make-it-reusable) in SWR documentation, I created a hook called `useRandomQuote`.

**Note:** In this project, I used [Quotable API](https://github.com/lukePeavey/quotable) for random quotes.

This hook is a wrapper for `useSWR` hook.

In my case, the API returns an array with one element which is the random quote. Since `data` is `undefined` during the request, I used [optional chaining](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining#optional_chaining_with_expressions).

And, the hook returns an object that contains the `quote` variable with the variables destructured from `useSWR` hook.

**Let's check the code and inspect it:**

```javascript
import useSWR from 'swr/immutable';

const useRandomQuote = () => {
  const { data, ...restSWR } = useSWR(
    'https://api.quotable.io/quotes/random',
    fetcher
  );

  return {
    ...restSWR,
    quote: data?.[0],
  };
};

export { useRandomQuote };
```

In your projects, you almost always use `useSWR` hook.

**Take a closer look at the useSWR hook:**

```javascript
const { data, error, isValidating, isLoading, mutate} = useSWR(
  key,
  fetcher
);
```

* Firstly we imported `useSWR` hook.
    
* Then we used it in our custom hook with two parameters: `key` and `fetcher`.
    
    `key` is a unique string for the request which is like an id.
    
    `fetcher` is an async function that accepts `key` and returns `data`.
    
* Finally, it returns `data`, `error`, `isValidating`, `isLoading`, and `mutate` variables.
    
    `data` is the variable returned from `fetcher`. During the first request, it will be `undefined`.
    
    `error` is the error thrown by `fetcher`. If there is no error, it will be `undefined`.
    
    `isValidating` is a boolean that indicates the request's status. It is `true` during each request including the first request.
    
    `isLoading` also is a boolean that indicates the **first** request's status. It is `true` during the **first** request, then it will always be `false`.
    
    `mutate` is a function that is used to modify the data manually.
    

If you noticed, I imported `useSWR` hook from `swr/immutable` in the first code snippet. It simply disables SWR's auto-revalidation. I prefer to use it because I want to revalidate the data manually with `mutate` function.

#### Understanding Auto-Revalidation

If the data you used is stale, SWR revalidates the data (re-fetches from the server) to keep freshness.

By default, SWR automatically revalidates the data (It assumes that the data is stale) in three cases:

1. Every time the component is mounted, even if there is data in the cache, it revalidates.
    
2. It revalidates when the window gets focused.
    
3. It revalidates when the browser regains its network connection.
    

### 3\. Mutating the Data

If you want manually revalidate the data, you can use `mutate` function.

I have `QuoteCard` component that displays the current quote. This component has a `New Quote` button that handles the mutation of the quote.

```javascript
const QuoteCard = () => {
  const { quote, isValidating, mutate } = useRandomQuote();

  return (
    {/* ... */}
    <button
      // ...
      onClick={() => mutate()}
    >
      New Quote
    </button>
    {/* ... */}
  )
}
```

When the mutate function is called, SWR revalidates the data. During this process, the `quote` variable remains the same (will not be undefined), and the `isValidating` variable becomes `true`.

**Here is a diagram of this process:**

[![A Diagram illustrating the fetch and revalidate pattern in SWR.](https://swr.vercel.app/_next/static/media/fetch-and-revalidate.3ebb9990.svg)](https://swr.vercel.app/docs/advanced/understanding#fetch-and-revalidate)

### 4\. Handling Concurrent Requests

If you don't handle request cancellation manually, the ongoing request continues even if the user initiates a new request alongside it, resulting in multiple concurrent requests.

SWR only updates the data after the last request is completed. If there are concurrent requests, their responses aren't important except for the last one. So if you don't cancel these requests, it results in unnecessary network usage.

I faced the same issue in my project. When the user clicks the `New Quote` button while a request is still loading, the application triggers a new request alongside the existing one.

![Visualization of concurrent requests being triggered by clicking the New Quote button continuously.](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e4dnmh15wlnp93iu80ge.gif)

Although I checked SWR's documentation, I couldn't find a built-in solution for this issue. (I also checked [React Query](https://tanstack.com/query/latest), and it has a built-in solution for that. I am planning to experiment with it in my next project involving API usage.)

In this scenario, I could use `AbortController` to handle request cancellation, but I didn't use it to keep things simple. I just disabled the `New Quote` button during validation.

## Conclusion

SWR helped me a lot in this project. If you have not used it previously, I highly recommend trying it in your future projects.

This is my first blog post, and I will be waiting for your feedback and thoughts about the library in the comments.

---

## Stay in Touch

* [Twitter](https://twitter.com/femincan)
    
* [LinkedIn](https://www.linkedin.com/in/femincan)
    
* [GitHub](https://github.com/femincan)
    

## Resources

* [SWR Documentation](https://swr.vercel.app/docs)
    
* [Revalidating options of SWR](https://koba04.medium.com/revalidating-options-of-swr-4d9f08bee813) by *Toru Kobayashi*
    
* My inspiration to use this library comes from [this](https://www.youtube.com/watch?v=Kjkx2BASAZA) video by [CoderOne](https://www.youtube.com/@CoderOne). (I know this video is about React Query, but I wanted to try SWR first.)