T
TanStack2y ago
deep-jade

fetchQuery

Is it possible to use fetchQuery with a staleTime of 1 hour and a gcTime of Infinity, so every time it should just return the cached data but after one hour it should refresh the cache, BUT in the background so when i call it, it should still return me the data directly since it has it in cache? Im doing this
router.beforeEach(async (route) => {
const queryClient = inject('queryClient', new QueryClient())
const data = await queryClient.fetchQuery({
queryKey: ['auth', 'getMe'],
queryFn: async () => {
const data = await authService().getMe()
return AuthUserModel(data.data)
},
staleTime: 1000 * 60 * 60, // 1 hour
gcTime: Infinity,
})
if (route.meta.requiresAuth && !data.id) {
// User is logged out invalidate all queries!
queryClient.invalidateQueries()
return { name: 'auth-login' }
}
})
router.beforeEach(async (route) => {
const queryClient = inject('queryClient', new QueryClient())
const data = await queryClient.fetchQuery({
queryKey: ['auth', 'getMe'],
queryFn: async () => {
const data = await authService().getMe()
return AuthUserModel(data.data)
},
staleTime: 1000 * 60 * 60, // 1 hour
gcTime: Infinity,
})
if (route.meta.requiresAuth && !data.id) {
// User is logged out invalidate all queries!
queryClient.invalidateQueries()
return { name: 'auth-login' }
}
})
on every page navigation i check if the user is authenticated, but i don't want the user to wait until the call is finished, so after an hour the call will still return the data from cache but will do a refresh in the background?
7 Replies
deep-jade
deep-jadeOP2y ago
i found ensureQueryData but that ALWAYS return me the cached data, i still want it to refetch every hour, just want that refetch to happen in the background
conscious-sapphire
conscious-sapphire2y ago
with fetchQuery, if you call the function after one hour, it will wait for the new data to resolve you can use a combo of: - getQueryData to lookup if there is data (could be stale) - queryClient.getQueryCache().find({ queryKey }) to find the query in the cache - check for query.isStaleByTime(1000 * 60 * 60) and if it is, fire prefetchQuery() without awaiting it for a background update
deep-jade
deep-jadeOP2y ago
Thanks! will definitely implement this. But what is the point of having a gcTime when after stale time you still need to wait on the fetch to be completed? Sorry if this sounds stupid, its propably used for something else. wouldn't it be helpfully to have such a feature like: fetch data from cache, but refresh in the background so you only need to wait when there is nothing in the cache? so implementation would be something like
router.beforeEach(async (route) => {
const queryClient = inject('queryClient', new QueryClient())
const data = await queryClient.fetchQuery({
queryKey: ['auth', 'getMe'],
queryFn: async () => {
const data = await authService().getMe()
return AuthUserModel(data.data)
},
staleTime: Infinity,
gcTime: Infinity
})

// Refresh data if staleTime is older than one hour
const cache = queryClient.getQueryCache().find({ queryKey: ['auth', 'getMe'] })
if (cache?.isStaleByTime(1000 * 60 * 60)) {
queryClient.prefetchQuery({
queryKey: ['auth', 'getMe'],
queryFn: async () => {
const data = await authService().getMe()
return AuthUserModel(data.data)
}
})
}

if (route.meta.requiresAuth && !data.id) {
// User is logged out invalidate all queries!
queryClient.invalidateQueries()
return { name: 'auth-login' }
}
})
router.beforeEach(async (route) => {
const queryClient = inject('queryClient', new QueryClient())
const data = await queryClient.fetchQuery({
queryKey: ['auth', 'getMe'],
queryFn: async () => {
const data = await authService().getMe()
return AuthUserModel(data.data)
},
staleTime: Infinity,
gcTime: Infinity
})

// Refresh data if staleTime is older than one hour
const cache = queryClient.getQueryCache().find({ queryKey: ['auth', 'getMe'] })
if (cache?.isStaleByTime(1000 * 60 * 60)) {
queryClient.prefetchQuery({
queryKey: ['auth', 'getMe'],
queryFn: async () => {
const data = await authService().getMe()
return AuthUserModel(data.data)
}
})
}

if (route.meta.requiresAuth && !data.id) {
// User is logged out invalidate all queries!
queryClient.invalidateQueries()
return { name: 'auth-login' }
}
})
conscious-sapphire
conscious-sapphire2y ago
fetch data from cache, but refresh in the background so you only need to wait when there is nothing in the cache?
on component level, this is exactly what the QueryObserver does. But I do see that for queryClient.fetchQuery, it would be nice if it also behaves that way: - if data is fresh, return it immediately - if data is stale, return it immediately and call prefetchQuery() in the background for the next consumer - if there is no data in the cache (either first hit or after gcTime), await the fetch and return that I think fetchQuery could behave like that, but it's a breaking change in behaviour ... Not sure if adding another function to the queryClient (with that behaviour) would be good. What would we name that ?
deep-jade
deep-jadeOP2y ago
so gcTime is used for the QueryObserver only right now? I totally understand this is a breaking change because people rely on how it works now. I would propose adding a parameter to the fetchQuery function. We can call this parameter, prefetchOnStale or prefetchWhenStale. However adding a new parameter does make the api out of sync with useQuery. If we want it as a new function it would be best described as fetchQueryAndPrefetchWhenStale but thats to verbose, calling it fetchQueryAndPrefetch doesn't cover it.
conscious-sapphire
conscious-sapphire2y ago
no, gcTime is always used to remove unused data from the cache. unused data is data that has no observer though I think I would rather want to streamline this behaviour in a new major version I'll think about it; I'm not too happy with fetchQuery, as it doesn't really "fetch". prefetchQuery is also weird because it sounds like it only fetches if there is nothing in the cache (a pre-fetch), but that's not true. Need to think about this a bit more
deep-jade
deep-jadeOP2y ago
I made a pull request: https://github.com/TanStack/query/pull/6996 feel free to make your own or give feedback about changes or best practices I need to use. First ever open source pull request for me.
GitHub
feat(fetchQuery): add 'prefetchWhenStale' option by andredewaard · ...
add a prefetchWhenStale property to the fetchQuery function. This allows the function to work like useQuery. if data is fresh, return it immediately if data is stale, return it immediately and cal...

Did you find this page helpful?