Can I fetch data only once when using swr?

Viewed 10498

For example, I switch to different page using react router:

const Apage = () => {
    const { data, error } = useSWR('/a-data', fetcher);
    return (
        <div>{data}</div>
    );
};

const Bpage = () => {
    const { data, error } = useSWR('/b-data', fetcher);
    return (
        <div>{data}</div>
    );
};

With swr, I can get data immediately when I'm not the first time access the page. But still, it calls the api to fetch data each time I access the page.

Can I only fetch data once if I dont need to revalidate the data is stale or not?

8 Answers

SWR 0.3.8

You should prevent automatic revalidation which is controlled by the next options:

{
  revalidateOnFocus: false,
  revalidateOnMount:false,
  revalidateOnReconnect: false,
  refreshWhenOffline: false,
  refreshWhenHidden: false,
  refreshInterval: 0,
}

According to the documentation refreshWhenOffline, refreshWhenHidden and refreshInterval are disabled by default, so it's enough only to set:

{
  revalidateOnFocus: false,
  revalidateOnMount:false,
  revalidateOnReconnect: false,
}

This will restrict SWR from running the fetching method. However, you still need the first one run to get your data.

You may end up with something like this:

const useStaleSWR = (dataKey) => {
  const revalidationOptions = {
    revalidateOnMount: !cache.has(dataKey), //here we refer to the SWR cache
    revalidateOnFocus: false,
    revalidateOnReconnect: false,
  };

  return useSWR(dataKey, fetcher, revalidationOptions);
}

SWR cache is exposed since 0.2.0 version


After all, I do not recommend using SWR for this purpose. SWR built to fetch data again. If you have static data - fetch once and store in session/local storage or define your own cache.

SWR concept is based on hooks. That means it means to use with local state, not for global state like mobx/redux/etc. Of course you can use with global state via React Context by creating your custom context. But you will prefer to use mobx/redux instead right?

So this is a caching strategy. If you prefer cache in memory, use mobx/redux. Otherwise, store in localStorage/cookie/etc.

Using this configuration makes the request called only once within an hour. If you need more time just increase the deduping interval.

 const { data, error } = useSWR('/api/get.json', fetcher, {
        dedupingInterval: 3600000,
        revalidateOnFocus: false,
        revalidateOnReconnect: false,
    });

You can do it in the top component like this

App.tsx

const { mutate } = useFoo()

useEffect(() => { 
mutate()
}, [mutate])

useFoo.ts

const useFoo = () => useSWR(key, fetcher, {
  revalidateOnFocus: false,
  revalidateOnMount: false,
  revalidateOnReconnect: false,
  refreshWhenOffline: false,
  refreshWhenHidden: false,
  refreshInterval: 0,
})

Disable Automatic Revalidations

Since version 1.0, SWR provides a helper hook useSWRImmutable to mark the resource as immutable:

import useSWRImmutable from 'swr/immutable'

// ...
useSWRImmutable(key, fetcher, options)

useSWR(key, fetcher, { revalidateIfStale: false, revalidateOnFocus: false, revalidateOnReconnect: false })

// equivalent to useSWRImmutable(key, fetcher)

It has the same API interface as the normal useSWR hook. You can also do the same thing by disable the following revalidation options:

useSWR(key, fetcher, {
  revalidateIfStale: false,
  revalidateOnFocus: false,
  revalidateOnReconnect: false
})

// equivalent to
useSWRImmutable(key, fetcher)

The revalidateIfStale controls if SWR should revalidate when it mounts and there is stale data.

These 2 hooks above do the exact same thing. Once the data is cached, they will never request it again.

Just use dedupingInterval, like:

   const { data } = useSWR(
        `https://api.thecatapi.com/v1/breeds?api_key=51e7b5a4-3b54-4fdf-a61a-84b653d85f8a`,
        fetcher,
        {
            dedupingInterval: 1000000,
        }
    );
Related