---
title: Understanding SWR
type: conceptual
summary: Understand how SWR works internally.
prerequisites:
  - /docs/getting-started
related:
  - /docs/advanced/cache
  - /docs/advanced/performance
---

# 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.

<img alt="A pattern for fetch and revalidate" src={__img0} />

### Key Change

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

<img alt="A pattern for key change" src={__img1} />

### Key Change + Previous Data

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

<img alt="A pattern for key change + previous data" src={__img2} />

### Fallback

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

<img alt="A pattern for fallback" src={__img3} />

### Key Change + Fallback

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

<img alt="A pattern for key change + fallback" src={__img4} />

### 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.

<img alt="A pattern for key change + previous data + fallback" src={__img5} />

## 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.

<Callout emoji="📝">
  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.
</Callout>

```jsx
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}
    </>
  );
}
```

<img alt="An example of using the isLoading state" src={__img6} />

You can find the code example [here](https://codesandbox.io/s/swr-isloading-jtopow)

## 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:

```jsx
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.

<Video src="https://user-images.githubusercontent.com/3676859/163695903-a3eb1259-180e-41e0-821e-21c320201194.mp4" caption="Keep previous search results when keepPreviousData has been enabled" ratio={640/730} />

You can find the full code for this example here: [https://codesandbox.io/s/swr-keeppreviousdata-fsjz3m](https://codesandbox.io/s/swr-keeppreviousdata-fsjz3m).

## 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](/docs/advanced/performance#dependency-collection).
