Dylan
Dylan

Reputation: 1118

SWR not pulling from cache

I've got a pretty basic component that does pagination. If I move pages, I'm trying to get SWR to pull from cache, but it does another api request instead.

Here is a Code.io sample. https://codesandbox.io/s/friendly-elgamal-v9sm9k?file=/src/App.js

If you look at the network tab after going to page 2, and back to page 1, it re-fetches page 1 from the api.

export const Stocks: React.FunctionComponent = () => {
  interface SearchResponse {
    Response: APIResponse<Array<string>>;
    SearchText: string;
  }
  const [pageIndex, setPageIndex] = useState<number>(1);

  const stocks = useRequest<Array<StockItem>>(`get-symbols?page=${pageIndex}`);

  const RenderSymbols = () => {
    console.log(stocks);
    if (stocks?.data == undefined) return;
    return stocks.data.map((f, index) => {
      return (
        <Stock key={index} item={f} />
      );
    })
  }
  return (
    <Grid container>
      <Grid item xs={12} xl={12}>
        <Typography variant='h4'>Stocks</Typography>
        <Grid container spacing={5}>
          {RenderSymbols()}
        </Grid>
        <Page page={pageIndex} totalItems={stocks.totalRecords} itemsPerPage={9} pageChanged={(p) => setPageIndex(p)} />
      </Grid>
    </Grid>
  );
};

export default Stocks; 

Anytime I go to the next page in the grid, it increment pageIndex, and SWR gets called here.

export default function useRequest<T>(url: string | null): Response<T> {
  
  const config: SWRConfiguration = {
    revalidateOnFocus: false,
  };

  const { data, mutate, error } = useSWR<APIResponse<T>>(`${process.env.REACT_APP_URL ?? ""}${url}`,fetcher,config);
  return {
    data: data?.data,
    isLoading: !error && !data,
    isError: error,
    mutate: mutate,
    page: data?.page ?? 0,
    totalRecords: data?.totalRecords ?? 0,
  };
} 

Here is my fetcher:

 export default async function fetcher<JSON = any>(
    input: RequestInfo,
    init?: RequestInit
  ): Promise<JSON> {

    const res = await fetch(`${input}`)

    return res.json()
  } 

Going back and forth between pages calls a new HTTP request, rather than grabbing it from SWR cache. I'm guessing I'm doing something wrong here, just not sure what.

Upvotes: 1

Views: 8035

Answers (2)

yqlim
yqlim

Reputation: 7098

SWR most certainly still uses the cached data (in SWR terms, the "stale data"). It's just that while using the stale data, it does a real request to retrieve the most updated data in the background, then updating it.

That's the main job of SWR, as stated in their home page:

SWR is a strategy to first return the data from cache (stale), then send the fetch request (revalidate), and finally come with the up-to-date data.

To prevent fetching newer data and use only stale data, turn the revalidateIfStale option off.

useSWR(url, fetcher, {
  ...config,
  revalidateIfStale: false  // default is `true`
});

Depending on your use cases, you probably want these options off too:

  • revalidateOnMount
  • revalidateOnFocus
  • revalidateOnReconnect

As the other answer said, you can also use useSWRImmutable, which turns all the above options off automatically for you.

Upvotes: 4

Danila
Danila

Reputation: 18536

If you don't want to revalidate the data at all it's better to use useSWRImmutable (more).

If you just want to increase cache TTL then you need to look into dedupingInterval option which is by default only equals to 2000ms

Upvotes: 2

Related Questions