swr: When revalidateOnMount = false, requests are never made

I configured globally revalidateOnMount = false and no requests are made. Doing a request for the first time when there is no cache yet should not be considered re-validation since there is no “re…” in that action. At least a request should be made on first mount.

In my project I want my requests to only be sent when there is no cache, in other words: after the first call to useSwr() I want all the the following useSwr() to use the cache during all the life time of the application, or until I call mutate(). This is the correct behavior in applications when data is not required to be up to date. I can’t figure out a global configuration where I can set this behavior, is it possible?

This is my global configuration:

{
   refreshInterval: 0,
   errorRetryCount: 0,
   shouldRetryOnError: false,
   revalidateOnMount: false,
   revalidateOnFocus: false,
   revalidateOnReconnect: false,
   compare: (a, b) => a === b
}

I’m very surprised about having to search for this or open an issue because of this, maybe I’m doing something that nobody should do or something like that. Also I can’t figure out what is the use case for the current revalidateOnMount = false, who would ever need a useSwr() that does nothing?

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Reactions: 20
  • Comments: 18 (2 by maintainers)

Most upvoted comments

What is the difference between revalidateOnMount and revalidateIfStale? I don’t really get it from the docs.

I completely agree with this. A cache-first query would be ideal here, similar to Apollo. If data exists, good, otherwise query.

Yeah I’ve been thinking about this too, that’s why I opened #992 specifically for this case: don’t fetch if cached.

I will try to add it in 1.0 soon, it would be great to hear more community feedback for it.

This really threw me too, the docs don’t allude to this setup either.

From the way the docs read, it would prevent a refetch on mount, effectively making the setup cached first.

Seems a bit of a pointless option as initialData also forces this behaviour too.

useSWRImmutable - is not a full solution given it forces all the other properties to false. In our case for example I wanted to keep the revalidateOnFocus and refreshInterval - it’s just “on mount” is triggered when any component using that key is mounted, and that can happen more often than I need to revalidate the data…

From what I could test the behaviour achieved by what most people expect revalidateOnMount: false is achieved by revalidateIfStale: false (although it does have some other side effects).

Hi all! With swr@beta you can use the new hook already:

import useSWRImmutable from 'swr/immutable'

You can use it with “immutable” resources (those do not change over time). And the hook works just like useSWR, but only fetches if the data is not cached:

useSWRImmutable(key, fetcher)

Let me know if there’s any questions! Going to close this issue for now.

This workaround works fine

const { data, error, mutate } = useSWR(key, fetcher, {
  revalidateOnFocus: false,
  revalidateOnMount: false,
  revalidateOnReconnect: false
})
useEffect(() => {
  if (data === undefined)
    mutate(undefined, true)
}, [key])

(if your fetcher doesn’t return undefined)

I agree this is not an expected behavior for revalidateOnMount. https://github.com/vercel/swr/blob/master/test/use-swr-integration.test.tsx#L48 Looks like the test also expects no fetching is made if revalidateOnMount: false. Does anyone know why?

By the way, I found a solution to only call the data if it is not in the cache. But then I can’t think of a use case for revalidateOnMount = false.

I agree with everyone in this thread. I was banging my head trying to get the same config that @fermmm is looking for.

It seems sensible to me that revalidateOnMount: false should do an initial fetch when cache is empty for the given key.

Or if there is a good reason for the current revalidateOnMount behavior then I may suggest a singleFetchMode: true config option that gives the behavior we’re all looking for.

Or at minimum can revalidateOnMount be renamed to work. Then work: false will make sense 😆

Jokes aside 😁 I would really really love to see this usecase addressed before 1.0 🙏.

By the way, I found a solution to only call the data if it is not in the cache. But then I can’t think of a use case for revalidateOnMount = false.

I was using that workaround but has some limits: Uses a useEffect to check if a cache exists and returns the cache, otherwise request. If you change the key nothing happens because there is data on the cache and it’s only checking for that, you can try to fix it by adding a useEffect to call mutate() when the key is different but then you can’t have a cache for each key because mutate() only makes a request, so in that key changing situation you have no cache and more requests are sent to the server just because of this SWR issue. For example, let’s suppose each pair of lines is a render of the same component:

userId = 01 useFixedSwr(´users/${userId}´) // Sends a request (no cache)

userId = 02 useFixedSwr(´users/${userId}´) // Sends a request (no cache)

userId = 01 useFixedSwr(´users/${userId}´) // Sends a request and should be using cache because user id 01 was already requested

This makes me think that maybe this issue is structural or something