Capítulo 35 de 80
queryClient.query() (the same method useQuery calls internally) is also the general-purpose prefetch primitive — call it ahead of when data is needed (on hover, in a parent component, inside another query's queryFn, at the router level) to flatten waterfalls without changing the eventual useQuery call.
queryClient.query() semantics for prefetching: runs the query function, caches the result, returns it, and throws on error — respects the client's default staleTime unless you pass one explicitly; non-critical prefetches should have their promise discarded (void ...().catch(noop)) since a normal useQuery will retry anyway. Un-consumed prefetched data (no matching useQuery ever mounts) is still garbage-collected after gcTime.queryClient.infiniteQuery({..., pages: 3}) prefetches multiple pages up front (default is just the first page) — requires getNextPageParam to walk forward.queryClient.query() from onMouseEnter/onFocus on an interactive element likely to need the data next — pair with a real staleTime so hover-prefetch isn't silently skipped as "already fresh."useQuery for the child's data in the parent too, ignoring the result (optionally with notifyOnChangeProps: [] to avoid extra re-renders) — this starts the fetch immediately in parallel with the parent's own query, without hoisting the actual consumption.useSuspenseQuery can't be used to prefetch (it would block rendering); use usePrefetchQuery/usePrefetchInfiniteQuery before a <Suspense> boundary instead, optionally wrapping the "secondary" data's own suspending consumer in its own nested boundary so it doesn't block the "primary" content.queryFn: when fetching A reliably means B will be needed too, kick off queryClient.query() for B from inside A's own queryFn — loads both in parallel without touching the calling component at all.queryFn (conditionally, based on the parent's response) loads the child's data in parallel with the child's JS chunk — the cost is including that data-fetching code in the parent's bundle instead of the lazy chunk, a tradeoff to make based on how common that code path is.await critical data so the route doesn't render until it's ready (letting error boundaries catch fetch failures), or fire-and-forget secondary data so rendering isn't blocked on it. staleTime: 'static' in a loader avoids double-fetching when the data's already cached and fresh enough.queryClient.setQueryData(key, data) to seed the cache directly.// Prefetch on hover, ahead of a click that will need the data
const prefetch = () => {
void queryClient.query({ queryKey: ['details'], queryFn: getDetailsData, staleTime: 60000 }).catch(noop)
}
<button onMouseEnter={prefetch} onFocus={prefetch}>Show Details</button>
// Suspense-safe prefetch before a boundary
function ArticleLayout({ id }) {
usePrefetchQuery({ queryKey: ['article-comments', id], queryFn: getArticleCommentsById })
return <Suspense fallback="Loading article"><Article id={id} /></Suspense>
}
usePrefetchQuery pattern that avoids blocking the boundary it sits in front of.queryClient.query() is the one primitive behind every prefetch pattern in this chapter — event handlers, component-lifecycle prefetch, and inside-queryFn prefetch are all the same call in different places.usePrefetchQuery/usePrefetchInfiniteQuery before a boundary — useQuery or useSuspenseQueries used naively for prefetching either doesn't start early enough or blocks rendering.