Open Menu

    Data fetching in React. Discover the power of useSWR hooks by Vercel!

    Flavio Del Grosso

    Flavio Del GrossoFeb 4, 2023

    4 min read939 words

    Hey everyone, Vercel recently released version 2.0 of their data fetching hooks, known as useSWR. This is a significant update that comes with several new features and improvements.

    If you don't know Vercel or Next.js I recommend you to give a look here.

    useSWRMutation hook

    At its core, useSWR is a hook for fetching data in React, much like the powerfull React Query that I love so much. It now includes a useSWRMutation hook that allows you to send requests by first passing in a key and then the request function. The hook returns a trigger function and a isMutating boolean indicating whether it is mutating or not.

    Here some examples from their documentation:

    javascript

    import useSWRMutation from 'swr/mutation';
     
    async function sendRequest(url, { arg }) {
      return fetch(url, {
        method: 'POST',
        body: JSON.stringify(arg),
      });
    }
     
    function App() {
      const { trigger, isMutating } = useSWRMutation('/api/user', sendRequest);
     
      return (
        <button disabled={isMutating} onClick={() => trigger({ username: 'johndoe' })}>
          {isMutating ? 'Creating...' : 'Create User'}
        </button>
      );
    }

    Optimistic updates

    One of the main use cases for this hook is optimistic UI. When you update data on a distant server with low latency, it can take some time for the update to reflect in the UI. To address this, you can use an optimistic update, which updates the data on the frontend before getting confirmation from the server.

    For example, if you're fetching a list of any data from an API, you can use the mutate function after adding a new item to refresh the data and pass in optimistic data. If the mutation is successful, you can set populateCache to true and revalidate to false, making the optimistic data the new source of truth.

    javascript

    const { mutate, data } = useSWR('/api/todos');
     
    return (
      <>
        <ul>{/* Display data */}</ul>
     
        <button
          onClick={() => {
            mutate(addNewTodo('New Item'), {
              optimisticData: [...data, 'New Item'],
              populateCache: true,
            });
          }}
        >
          Add New Item
        </button>
      </>
    );

    Rolling back

    In case the mutation fails, you can use the rollbackOnError option, which is enabled by default, to roll back the optimistic update.

    Preloading data

    In addition to the mutation hook, useSWR also includes a preload function that lets you load data as soon as the JavaScript module is in scope. This means you can start preloading the data before React even begins to render anything! If you've already preloaded the data, useSWR will fall back to it and avoid duplicating the preloading process.

    javascript

    import useSWR, { preload } from 'swr';
     
    const fetcher = (url) => fetch(url).then((res) => res.json());
     
    // You can call the preload function in anywhere
    preload('/api/user', fetcher);
     
    function Profile() {
      // The component that actually uses the data:
      const { data, error } = useSWR('/api/user', fetcher);
      // ...
    }
     
    export function Page() {
      return <Profile />;
    }

    isLoading and isValidating states

    The hook also includes a new state, isLoading, which only triggers when the data is being fetched for the first time, as opposed to isValidating which triggers every time the data is revalidated.

    keepPreviousData feature

    And finally, last but not least, the feature keepPreviousData, it lets you hold onto data even after it's been fetched, enhancing the user experience in real-time situations, like with live search. This is especially handy when the search resource's key is constantly changing.

    javascript

    function Search() {
      const [search, setSearch] = React.useState('');
     
      const { data, isLoading } = useSWR(`/search?q=${search}`, fetcher, {
        keepPreviousData: true,
      });
     
      return (
        <div>
          <input type="text" value={search} onChange={(e) => setSearch(e.target.value)} placeholder="Search..." />
     
          <div className={isLoading ? 'loading' : ''}>
            {data?.products.map((item) => (
              <Product key={item.id} name={item.name} />
            ))}
          </div>
        </div>
      );
    }

    Overall, I think useSWR hook is a fantastic addition to the React data fetching ecosystem. And now, are you thinking to start using it?


    Share on