T
TanStack•2y ago
deep-jade

Why ensureQueryData instead of prefetchQuery?

This question is overlapping with #query , but posting it here since I am asking about the usage of react-query in react-router: The react-router documentation and the react-router examples based on react-query all use code like this:
loader: ({ context: { queryClient } }) =>
queryClient.ensureQueryData(postsQueryOptions),
loader: ({ context: { queryClient } }) =>
queryClient.ensureQueryData(postsQueryOptions),
Wouldn't it be better to use prefetchQuery instead of ensureQueryData here? Quoting from the react-query docs (see https://tanstack.com/query/v4/docs/react/reference/QueryClient#queryclientfetchquery)
If the query exists and the data is not invalidated or older than the given staleTime, then the data from the cache will be returned. Otherwise it will try to fetch the latest data.
Whereas ensureQueryData does not check if the data is invalidated (see https://tanstack.com/query/v4/docs/react/reference/QueryClient#queryclientensurequerydata)
ensureQueryData is an asynchronous function that can be used to get an existing query's cached data. If the query does not exist, queryClient.fetchQuery will be called and its results returned.
I saw a difference for the following use case: I have a list view, and a separate detail view. When data is modified in the detail view, the query key of the list view is invalidated and then navigates back to the list view. With ensureQueryData: When the list view is shown after data modification, it briefly shows the outdated data, fetches the updated data from the backend and then refreshes the list to show the latest state. With prefetchQuery, the list view never shows the outdated item.
QueryClient | TanStack Query Docs
QueryClient The QueryClient can be used to interact with a cache:
4 Replies
adverse-sapphire
adverse-sapphire•2y ago
I figured that it would be better to see stale data quickly and invalidate in the background rather than force the navigation to wait for the fresh data. You could obviously do either. @TkDodo 🔮 what’s your recommendation here?
equal-aqua
equal-aqua•2y ago
It really depends on what you prefer. I'd also generally rather see stale data quickly than wait for new data. See: https://tkdodo.eu/blog/react-query-meets-react-router#getquerydata--fetchquery After invalidations, where you expect new data, it might be the opposite. What you can do here is to return the promise from invalidateQueries in onSuccess, so that the mutation stays pending until the refetch is finished. Only then you'd navigate, in which case ensureQueryData would be instant again.
React Query meets React Router
React Query and React Router are a match made in heaven.
deep-jade
deep-jadeOP•2y ago
hmm I already return the promise:
const createConfigurationMutation = useMutation({
mutationFn: createConfiguration,
onSuccess: () =>
queryClient.invalidateQueries({ queryKey: queries.list.queryKey }),
});
const createConfigurationMutation = useMutation({
mutationFn: createConfiguration,
onSuccess: () =>
queryClient.invalidateQueries({ queryKey: queries.list.queryKey }),
});
is this what you meant?
equal-aqua
equal-aqua•2y ago
yes. okay thinking about it some more, of course the list query isn't mounted when the mutation finishes, so invalidation will only mark it as stale. You could to queryClient.refetchQueries instead, or go with the fetchQuery approach instead of ensureQueryData. There are lots of ways to rome here 🙂

Did you find this page helpful?