Supercharging data fetching in React with SWR
3 min read

Supercharging data fetching in React with SWR

The default way to fetch data in React applications is good. There is a better way and is super fun to use. It's called SWR.
Supercharging data fetching in React with SWR

## What is SWR?

Typically, when we call a REST API, we use `fetch` or a third-party library like `axios`, or, god forbid, `$.ajax` and `XHR`. The browser then makes an HTTP call and accepts a response. While the call is being made, the user waits, usually staring at a loading indicator.

SWR enhances data fetching with caching, revalidation, and request deduplication. The name "SWR" is derived from `stale-while-revalidate`, an HTTP cache invalidation strategy. It is back-end agnostic and supports TypeScript. It exposes React hooks that we can use for data fetching in our applications.

## Why use SWR instead of fetch/axios?

When we use SWR for data fetching, it returns the data from cache (stale), then sends the request (revalidate) and returns the up-to-date data. SWR will automatically cache the response the first time we fetch it.

This translates to a real-time experience for users who instantly see UI being rendered on-screen, while our application fetches the up-to-date data. SWR also has some cool features out-of-the-box:

-   Auto revalidation
-   Support for React Suspense
-   Fast page navigation
-   Pagination
-   Scroll position recovery
-   Retry on error

## Why do we still need fetch/axios when using SWR

SWR does not replace native `fetch` or `axios`. We'll end up using them anyway because SWR only wraps around them. One of the arguments we pass to the `useSWR` hook is a fetcher function that uses `fetch` or `axios`.

```js
// Using Fetch API
export const fetcher = async (url, opts = {}) => {
  const res = await fetch(url, opts);
  if (!res.ok) {
     throw new Error('Error completing request');
  }

  return await res.json();
};
```

We can then use the `useSWR` hook to fetch data.

```js
const { data, error } = useSWR(`/api/users/${userId}`, fetcher);
```

We can also configure SWR globally in our applications. We can skip passing the fetcher function if we do this:

```js
function App({ Component, pageProps }) {
  return (
     <SWRConfig value={{ fetcher }}>
        <Component {...pageProps} />
     </SWRConfig>
  );
}
```

The real power of using SWR shows when you can reuse data fetching code. When building an application, we might need to reuse the data we fetch in multiple places. SWR makes it incredibly easy to create custom data fetching hooks that we can use in any of our components.

```js
export function useUser(userId) {
  const { data, error } = useSWR(`/api/users/${userId}`, fetcher);
  return {
     user: data?.user,
     isLoading: !error && !data,
     isError: error,
  };
}
```

Now we can use the `useUser` hook in our components like this:

```js
function Profile({ userId }) {
  const { user, isLoading, isError } = useUser(userId);

  if (isLoading) return <div>Loading...</div>;
  if (isError) return <div>An error occurred...</div>;

  return (
     <div>
        <img src={user.avatar} />
        <span>{user.name}</span>
        <span>{user.email}</span>
     </div>
  );
}
```

## Configuring revalidation

SWR offers multiple revalidation strategies. We can use one or all of them. We can also pick and choose which of our fetch requests use which strategies. We can also globally configure revalidation strategies in `SWRConfig` provider.

-   **Revalidation on focus**: When the tab comes into focus, SWR will revalidate. Enabled by default.
-   **Revalidation on network recovery**: When our device reconnects to the internet, SWR will revalidate. Enabled by default.
-   **Polling on interval**: It can automatically make fetch requests at specified intervals so our UI is always up-to-date. Disabled by default. If enabled, there are two more options that we can use to enable polling even when the browser tab is not active or when we're not connected to the internet.

## Mutation

SWR will revalidate our data when one of the above strategies is used. We can also manually trigger revalidation using `mutate(key)`. The `key` is the URL where we fetch the data.

```js
mutate(`/api/users/${userId}`);
```

The `useSWR` hook also returns a `mutate` function that we can use which doesn't need a `key`.

```js
const { user, mutate } = useSWR(`/api/users/${userId}`, fetcher);
```

## POST requests

SWR lets us do optimistic rendering by local mutation — where we update the UI based on new data immediately — before we even update the database with POST requests.

```js
const { user } = useUser(userId);

...

const formSubmitHandler = async (values) => {
  // Update local data immediately and disable revalidation
  mutate(`/api/users/${userId}`, { ...user, ...values }, false);

  // Make the API request to update the database
  await updateUser(values);

  // Trigger revalidation to ensure local data is correct
  mutate(`/api/users/${userId}`);
}
```

---

SWR is a better way to fetch data in our React applications. It abstracts away many features that we normally would have written ourselves if our application requires them. It also gives us good defaults so we don't have to spend a lot of time in configuration. Most important of all, it has a simple API and is easy to use.

There is also an alternative to SWR called [`react-query`](https://react-query.tanstack.com/) which I haven't used, yet. I'll cover that in a future post.