Onyx
Onyx

Reputation: 5782

How to tell React Query fetchQuery to make a new GET request and not used the already cached response?

I have the following function that makes a GET request for my user information and caches it using react query's fetchQuery so that every call after the first one does not make a GET request and instead just pulls the data from the cache.

export const getVegetables = async () =>
    await queryClient.fetchQuery(['getVegetables'], async () => {
        try {
            const { data } = await request.get('/vegetables');

            return data;
        } catch (error) {
            throw new Error('Failed to fetch vegetables');
        }
    });

The problem is that now I actually want to make a new GET request in order to check if the user data has changed, but calling getVegetables() pulls from the cache. How can I instruct fetchQuery to make a fresh GET request and not used the cache?

Upvotes: 0

Views: 3292

Answers (3)

TkDodo
TkDodo

Reputation: 28853

fetchQuery will always fetch unless there is data in the cache that is considered fresh. This is determined by the staleTime setting.

staleTime defaults to 0 - which means "immediately stale". So the code you are showing that is calling fetchQuery should always fetch - unless you have a global staleTime set. You're not showing this in your code, but I guess this must be the reason. Note that fetchQuery doesn't know about staleTime being set by other observers (created by useQuery).

Now if you have a globally set staleTime and that is affecting fetchQuery, but you still want to always fetch, the best thing you can do is pass staleTime: 0 directly to fetchQuery. Again, this is the default behaviour, so it's only necessary if you have a global staleTime set:

await queryClient.fetchQuery(
  ['getSelf'],
  async () => { ... },
  { staleTime: 0 }
)

Upvotes: 0

Chad S.
Chad S.

Reputation: 6633

A slight modification to your function will allow you to first invalidate the query (which will remove it from the cache).

export const getSelf = async (skipCache = false) => {
    if(skipCache) { queryClient.invalidateQueries(['getSelf']); }
    
    return queryClient.fetchQuery(['getSelf'], async () => {
        try {
            const { data } = await request.get('/users/me');

            // @todo: This sideloads a bunch of stuff, that we could cache
            return data;
        } catch (error) {
            throw new Error('Failed to fetch user information');
        }
    });
}

Upvotes: 1

Oleg Brazhnichenko
Oleg Brazhnichenko

Reputation: 652

In case of using fetchQuery, you can set cacheTime to 0 in query options, so every time you call it, it will suggest that cache is outdated and fetch fresh data, but I'd suggest you to use useQuery.

Here you can read about difference between useQuery and fetchQuery

The best way is to use useQuery hook and invalidate that query.

import { useQueryClient } from '@tanstack/react-query'

// Get QueryClient from the context
const queryClient = useQueryClient()

queryClient.invalidateQueries({ queryKey: ['getSelf'] })

After invalidation, it will immediately fetch fresh data.

Upvotes: 1

Related Questions