Cool Boiled WaterCool Boiled Water Logo
HomeBlog
useSWR

Understanding SWR in React: Basics to Advanced

React
2024 Dec 02671 words|Estimated reading time: 4 minutes

In React app development, managing data is crucial. SWR (Stale-While-Revalidate) is a powerful data fetching and caching library that simplifies data retrieval and state updates in applications. This article will start with basic concepts of SWR and then delve into how to use it in React for handling data fetching and state management.

1. Introduction to SWR

SWR is a React Hooks library that offers a simple yet powerful way to handle data fetching and caching. Its core idea is to provide stale data while fetching, and update data in the background to keep it fresh. This pattern not only improves application performance but also enhances user experience.

2. Basic Usage

The simplest way to use SWR is through the useSWR hook function. In TypeScript, defining data types and implementing generics is easy.

import useSWR from 'swr';

interface UserData {
  id: number;
  name: string;
}

const fetcher = (url: string) => fetch(url).then(res => res.json());

export function Nav() {
  const { data, error, isLoading } = useSWR<UserData>('/api/user', fetcher);

  if (error) return <div>Failed to load</div>;
  if (isLoading) return <div>Loading...</div>;

  return (
    <div>
      <h1>Hello, {data.name}!</h1>
    </div>
  );
};

Also, you can use fallback data to return something earlier than the real query.

const { data, error, isLoading } = useSWR<Post>(`/api/post/${postId}`, fetcher, {
    fallbackData: {
      id: postId,
      title: 'Loading...',
      content: 'Loading...',
    },
});

4. Global Configuration

SWR also provides global configuration options to customize its behavior. For instance, you can configure global cache time (default is 0ms, but if set, all SWRs under this configuration will automatically request at intervals, essentially polling), error retry strategies, etc.

import { SWRConfig } from 'swr';

export function App({ children }) {
  return (
    <SWRConfig
      value={{
        refreshInterval: 3000,
        fetcher: (url: string) => fetch(url).then(res => res.json()),
      }}
    >
      {children}
    </SWRConfig>
  );
};

With this configuration, you no longer need to write a separate fetcher function. However, if there's additional logic in the API, SWR itself supports overriding.

5. Best Practices with mutate

SWR also offers the mutate method to manually update data in the cache, i.e., updating the data returned by useSWR. Paired with optimistic updates, this can provide a very smooth API experience.

import useSWR, { mutate } from 'swr';

const updateUser = async (newName: string) => {
  await fetch('/api/user', { method: 'PUT', body: JSON.stringify({ name: newName }) });
  mutate('/api/user'); // Update data in cache
};

However, here you're actually using the global mutate function. You only need to write a corresponding key in the mutate function, which allows you to update data from other APIs. This is because SWR itself uses a hash table to store all request keys and puts the results together.

So, if you just want to call the current API again, it's more appropriate to use the mutate function exported by useSWR itself, like this:

const { data, mutate } = useSWR('/api/user', fetcher)

But if you want to call the global mutate, there's a better way:

import useSWR, { useSWRConfig } from "swr";

function Profile() {
  const { mutate } = useSWRConfig();
  const { data } = useSWR("/api/user", fetcher);

  const handleClick = async () => {
    const newName = data.name.toUpperCase();
    const user = { ...data, name: newName };
    const options = {
      optimisticData: user,
      rollbackOnError(error) {
        // Don't roll back if the error is due to timeout
        return error.name !== "AbortError";
      },
    };

    // Update local data immediately
    // Send a request to update data
    // Trigger revalidation to ensure local data correctness
    mutate("/api/user", updateFn(user), options);
  };

  return (
    <div>
      <h1>My name is {data.name}.</h1>
      <button onClick={handleClick}>Uppercase my name!</button>
    </div>
  );
}

The code above is already paired with optimistic updates, allowing us to make rapid modifications using predicted results, providing users with a silky smooth experience.

6. Other Intriguing Features

SWR boasts additional features such as conditional fetching and support for multiple arguments.

If you're interested in exploring these functionalities further, feel free to give them a try yourself!

Content

1. Introduction to SWR 2. Basic Usage 4. Global Configuration 5. Best Practices with mutate 6. Other Intriguing Features
Switch To PCThank you for visiting, but please switch to a PC for the best experience.