Skip to content
Docs
Advanced
Understanding SWR

Understanding SWR

State Machine

useSWR returns data, error, isLoading, and isValidating depending on the state of the fetcher function. This diagrams describe how SWR returns values in some scenarios.

Fetch and Revalidate

This pattern is to fetch data and revalidate it later.

A pattern for fetch and revalidate

Key Change

This pattern is to fetch data and change the key and revalidate it later.

A pattern for key change

Key Change + Previous Data

This pattern is to fetch data and change the key and revalidate it later with the keepPreviousData option.

A pattern for key change + previous data

Fallback

This pattern is to fetch data and revalidate it later with fallback data.

A pattern for fallback

Key Change + Fallback

This pattern is to fetch data and change the key and revalidate it later with fallback data.

A pattern for key change + fallback

Key Change + Previous Data + Fallback

This pattern is to fetch data and change the key and revalidate it later with the keepPreviousData option and fallback data.

A pattern for key change + previous data + fallback

Combining with isLoading and isValidating for better UX

Comparing to the existing isValidating value, isLoading is a new property that can help you for the more general loading cases for UX.

  • isValidating becomes true whenever there is an ongoing request whether the data is loaded or not
  • isLoading becomes true when there is an ongoing request and data is not loaded yet.

Simply saying you can use isValidating for indicating everytime there is an ongoing revalidation, and isLoading for indicating that SWR is revalidating but there is no data yet to display.

📝

Fallback data and previous data are not considered "loaded data," so when you use fallback data or enable the keepPreviousData option, you might have data to display.

function Stock() {
  const { data, isLoading, isValidating } = useSWR(STOCK_API, fetcher, {
    refreshInterval: 3000
  });
 
  // If it's still loading the initial data, there is nothing to display.
  // We return a skeleton here.
  if (isLoading) return <div className="skeleton" />;
 
  // Otherwise, display the data and a spinner that indicates a background
  // revalidation.
  return (
    <>
      <div>${data}</div>
      {isValidating ? <div className="spinner" /> : null}
    </>
  );
}

An example of using the isLoading state

You can find the code example here (opens in a new tab)

Return previous data for better UX

When doing data fetching based on continuous user actions, e.g. real-time search when typing, keeping the previous fetched data can improve the UX a lot. keepPreviousData is an option to enable that behavior. Here's a simple search UI:

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>
  );
}

With keepPreviousData enabled, you will still get the previous data even if you change the SWR key and the data for the new key starts loading again.

Keep previous search results when keepPreviousData has been enabled

You can find the full code for this example here: https://codesandbox.io/s/swr-keeppreviousdata-fsjz3m (opens in a new tab).

Dependency Collection for performance

SWR only triggers re-rendering when the states used in the component have been updated. If you only use data in the component, SWR ignores the updates of other properties like isValidating, and isLoading. This reduces rendering counts a lot. More information can be found here.