DEV Community

Abhinav Sawarkar
Abhinav Sawarkar

Posted on

Supercharge Your Data Fetching with Optimistic UI, Preload, and Error Handling Using SWR

SWR (Stale-While-Revalidate) is a powerful library that provides a robust solution for data fetching, caching, and error handling. In this blog, we will dive into the core concepts of SWR, including optimistic UI, preloading data, and handling errors with rollbackOnError. We'll explore each concept in detail and provide code examples to demonstrate their usage and benefits.

SWR and Data Fetching:
SWR is a JavaScript library that leverages the concept of "stale-while-revalidate" to fetch and cache data. It aims to provide a seamless user experience by displaying cached data while simultaneously revalidating it in the background. This approach improves performance and responsiveness by minimizing unnecessary requests.

Let's consider an example of fetching user data using SWR:

import useSWR from 'swr';

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

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

  if (error) {
    return <div>Error fetching user data.</div>;
  }

  if (!data) {
    return <div>Loading...</div>;
  }

  return (
    <div>
      <h1>{data.name}</h1>
      <p>{data.email}</p>
      {/* Render other user details */}
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

In this example, useSWR is used to fetch user data from the specified API endpoint (/api/users/${userId}). The fetcher function is responsible for making the HTTP request and returning the JSON response. The data and error returned by useSWR are used to conditionally render the UI based on the data fetching status.

Optimistic UI:
Optimistic UI is a powerful technique to provide instant feedback to users by optimistically updating the UI before the server responds. SWR makes it easy to implement optimistic UI by allowing you to mutate the data cache directly.

Let's extend the previous example to demonstrate optimistic UI:

import useSWR, { mutate } from 'swr';

// ...

function UserProfile({ userId }) {
  // ...

  const handleFollow = async () => {
    // Optimistic update
    mutate(`/api/users/${userId}`, { ...data, isFollowed: true }, false);

    // Make the actual API request
    try {
      await fetch(`/api/users/${userId}/follow`, { method: 'POST' });
      // Revalidate the data to fetch the latest changes
      mutate(`/api/users/${userId}`);
    } catch (error) {
      // Rollback on error
      mutate(`/api/users/${userId}`);
    }
  };

  return (
    <div>
      {/* Render user details */}
      {data.isFollowed ? (
        <button disabled>Following</button>
      ) : (
        <button onClick={handleFollow}>Follow</button>
      )}
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

In this example, the handleFollow function is triggered when the user clicks the "Follow" button. It first optimistically updates the UI by modifying the local data cache using mutate. Then, it makes the actual API request to follow the user. If the request is successful, the data is revalidated to fetch the latest changes. In case of an error, the cache is rolled back to maintain consistency.

Preload:
Preloading data is a crucial technique to improve perceived performance by fetching essential data in advance. SWR provides the mutate function with a data argument, allowing us to preload data into the cache.

Consider an example where we preload user data before rendering the UserProfile component:

import { SWRConfig, mutate } from 'swr';

// ...

function App() {
  useEffect(() => {
    const userId = 123;
    fetch(`/api/users/${userId}`).then((res) => {
      if (res.ok) {
        return res.json().then((data) => {
          // Preload the data into the cache
          mutate(`/api/users/${userId}`, data);
        });
      }
    });
  }, []);

  return (
    <SWRConfig value={{}}>
      <UserProfile userId={123} />
    </SWRConfig>
  );
}
Enter fullscreen mode Exit fullscreen mode

In this example, the App component preloads user data by making an initial request to /api/users/${userId} and storing the response in the cache using mutate. The UserProfile component is then rendered inside the SWRConfig provider, which enables SWR and allows the component to utilize the preloaded data.

RollbackOnError:
Handling errors gracefully is vital for a seamless user experience. SWR provides the rollbackOnError option to automatically revert the cache to its previous state in case of an error.

Let's modify our previous example to rollback the cache on error:

import useSWR from 'swr';

// ...

function UserProfile({ userId }) {
  const { data, error } = useSWR(`/api/users/${userId}`, fetcher, {
    rollbackOnError: true,
  });

  // ...
}
Enter fullscreen mode Exit fullscreen mode

By passing the rollbackOnError option as true, SWR will automatically rollback the cache to its previous state if an error occurs during data fetching. This ensures that the UI remains consistent and avoids displaying incorrect or outdated data.

SWR simplifies data fetching, caching, and error handling by leveraging the "stale-while-revalidate" concept. In this blog, we explored the core concepts of SWR, including data fetching, optimistic UI, preloading data, and rollbackOnError. By implementing these techniques, you can create high-performance web applications with seamless user experiences. SWR empowers developers to build efficient and responsive interfaces while keeping the codebase clean and maintainable.

Remember to refer to the official SWR documentation for further details and explore additional features offered by the library. Happy coding!

Top comments (0)