0

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.

Dylan
  • 1,068
  • 12
  • 25

2 Answers2

4

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.

yqlim
  • 6,898
  • 3
  • 19
  • 43
  • I've tried the exact same thing while just replacing useSWR with SWRImmutable, and it still does the fetch. So I'm not sure what the deal is there. – Dylan Aug 10 '22 at 16:36
1

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

Danila
  • 15,606
  • 2
  • 35
  • 67
  • I've tried the exact same thing while just replacing useSWR with SWRImmutable, and it still does the fetch. So I'm not sure what the deal is there. – – Dylan Aug 10 '22 at 16:37
  • How does your fetcher function look like? Or can you make a reproduction on https://codesandbox.io? You can use some fake api like https://jsonplaceholder.typicode.com/guide/ – Danila Aug 10 '22 at 17:07
  • I've added my fetcher to my original post. – Dylan Aug 10 '22 at 19:20
  • https://codesandbox.io/s/friendly-elgamal-v9sm9k?file=/src/App.js If you look at the network tab after going back and forth between pages, you can see it's fetching again. – Dylan Aug 10 '22 at 19:52
  • 1
    @Dylan You imported regular default import of `swr` package. To import immutable version use `import useSWRImmutable from "swr/immutable"` – Danila Aug 10 '22 at 20:56