T
TanStack•3y ago
afraid-scarlet

Does the `useQuery` caching against the `queryKey`?

I have this snippet and I'm expecting that the endpoint will requested any time the prunedFilter is changed as it is changing the key. * This is actually first expectation what failed, so I'm calling the refetch in the useEffect hook to achieve this behaviour. * Other expectation I have is that the endpoint will requested against query key, so if the changed prunedFilter will change back to previous state and therefore, the key will appear same as before, I'm expecting cached data, but it's requesting the server any time the prunedFilter is changed.
const { data, refetch, isRefetching } = useQuery<any, Error>(
["allQuestionsCorrelationData", prunedFilter],
() => {
const formData = new FormData();
formData.append("filter", JSON.stringify(prunedFilter));

return fetch(
"https://dev.any-survey.com/admin/interests/data.cfm/allQuestionsCorrelation/",
{
method: "POST",
body: formData,
}
)
.then((res) => res.json())
.then((d) => {
setCompData(d);
return d;
});
},
{ staleTime: Infinity, initialData: [] }
);
const { data, refetch, isRefetching } = useQuery<any, Error>(
["allQuestionsCorrelationData", prunedFilter],
() => {
const formData = new FormData();
formData.append("filter", JSON.stringify(prunedFilter));

return fetch(
"https://dev.any-survey.com/admin/interests/data.cfm/allQuestionsCorrelation/",
{
method: "POST",
body: formData,
}
)
.then((res) => res.json())
.then((d) => {
setCompData(d);
return d;
});
},
{ staleTime: Infinity, initialData: [] }
);
14 Replies
ambitious-aqua
ambitious-aqua•3y ago
I'm expecting that the endpoint will requested any time the prunedFilter is changed as it is changing the key.
yes, that's what it does. except that you pass initialData as an empty array, and set staleTime to Infinity, so the empty array goes into the cache and is treated as fresh forever, which is why the queryFn is never called unsurprisingly, I have a blog post on that topic: https://tkdodo.eu/blog/placeholder-and-initial-data-in-react-query
afraid-scarlet
afraid-scarletOP•3y ago
thanks, just going through But honestly, I think that initial settings I did is quite logic as the staleTime is not cacheTime and initialData should be an empty array. And that leads to not really correct behaviour I would to point.
ambitious-aqua
ambitious-aqua•3y ago
you're mixing up what cacheTime and staleTime are I think and if you want to show temporary data that shouldn't be cached, use placeholderData cacheTime just defines how long queries that are no longer used will stay in the cache. it has no effect on how long queries are actually cached. we'll rename this to something like inactiveCacheTime in the next major version
afraid-scarlet
afraid-scarletOP•3y ago
This seems to me to be related to the garbage collection ... correct? I think I have been correctly directed by other resources like docs and some other articles/examples to use the staleTime for data I want to keep forever. So I don't think it is necessary to rename the cacheTime ... to something else. More confusing is the placeholderData x initialData but I'm new with this library, still getting it into the veins
xenogeneic-maroon
xenogeneic-maroon•3y ago
Yes, cacheTime defines when to garbage collect queries that are no more observed
afraid-scarlet
afraid-scarletOP•3y ago
I've got what I wanted ... almost 🙂 .... I just need previous data for same endpoint but not same key ... as my key is generated from the filter used as a payload. But this seems to me that I need to cover this on my component as it doesn't make sense to return different data for different key Before I was using my own library to cover this, so in my case even the id was tied to the cache memory, the endpoint call was wrapped by the function.
ambitious-aqua
ambitious-aqua•3y ago
staleTime for data I want to keep forever.
I'll try again with a different explanation. react-query caches data that goes into the cache. staleTime defines if the data that is in there is still fresh. staleTime does nothing else, so it's not related to when data is removed from the cache. if data is considered stale, it will still be given to you instantly, and the query will be in success state, but data will be re-fetched in the background (stale-while-revalidate). if you set staleTime to Infinity, that means: if data is put into the cache once, I never want a refetch for as long as this data is in the cache because that data is fresh forever. --- cacheTime is related to garbage collection, as you said. queries that are actively used will never be removed, but queries that are unused (because you switched pages and the todo query is not shown anymore) can be removed from the cache after sometime. That time is cacheTime. But cacheTime only starts to "count" once the query becomes unused. So the current name is confusing because it feels like, with the default of 15 minutes, that data will be cached for 15 minutes, but in fact it will be cached for 15 minutes PLUS how long you are actively using the query - which could be forever. --- so if you want to make sure to only ever fetch once, you have to actually set both times to Infinity to be on the safe side. --- if you understood the above about staleTime, then also initialData should make sense. It puts data into the cache. staleTime doesn't care how data got into the cache. could be because useQuery did a fetch. or because you prefetched. Or because you hydrated from a server-side rendering. or because you called queryClient.setQueryData. or because you passed initialData. data in the cache is data in the cache. if you say this data is good forever (with staleTime: Infinity), there won't be an additional fetch.
afraid-scarlet
afraid-scarletOP•3y ago
ok thanks ... that makes more sense
ambitious-aqua
ambitious-aqua•3y ago
placeholderData on the other hand is not put into the cache. that's the big difference between the two. so data in the cache is still undefined, hence there will always be a background refetch
afraid-scarlet
afraid-scarletOP•3y ago
I think to understand it fully I would to know how the RQ knows that the query is unused. Another one. Lets pretend that the query will disappear with component (so it's unmounted), so query is unused but cached. If I'll create same query again with different component. Can I expect the data from the cache if they are still in the cache?
xenogeneic-maroon
xenogeneic-maroon•3y ago
Yep and depending on staleTime (and options like refetchOnMount) you could have or not a call to the queryFn
ambitious-aqua
ambitious-aqua•3y ago
I think to understand it fully I would to know how the RQ knows that the query is unused.
every time you call useQuery, you create an observer that "observes" a queryKey. if you have zero observers, the query is unused. you can see that in the devtools - the number on the left is the number of observers. If that number goes to zero, the query is clearly marked as inactive (grey state)
afraid-scarlet
afraid-scarletOP•3y ago
awesome ... I need to explore the devtools also ... I was working on similar library which is used on production servers for more then year and we discovered the react-query couple months back so we decide to replace it and it is quite mind blowing to see similar paths in the development. But mine was designed to be used from services first, not from components. During exploration the react-query I'm getting into states like "no I don't want it" vs "it's hell awesome" 😄 It mostly depends on what I ate before. Hello, another question I have ... if I have stale time set to 3 minutes and cache to 30 minutes, after create a component which will reuse the cache (which is not updated by any other component anymore), I suppose that the query data may not be fresh and I need to wait another 3 minutes after component creation to refetch.
xenogeneic-maroon
xenogeneic-maroon•3y ago
By default yes. But you could act on this with refetchOnMount Either by settings its value to always, or by defining a custom function to have more control on it.

Did you find this page helpful?