Start data loading before Suspense
A page renders a Suspense-wrapped child that reads data with useSuspenseQuery.
TanStack · Hook
usePrefetchQuery starts a query during render so a descendant behind Suspense can use the data without initiating the first fetch itself. It returns void and skips work when the query already has cached state.
usePrefetchQuery starts a query from render so data can be available before a descendant using useSuspenseQuery renders. It accepts the same query options as queryClient.query, requires a queryKey and usually a queryFn, and optionally accepts a custom QueryClient. It has no result value.
function usePrefetchQuery<TQueryFnData, TError, TData, TQueryData, TQueryKey>(options: UsePrefetchQueryOptions<TQueryFnData, TError, TData, TQueryData, TQueryKey>, queryClient?: QueryClient): void;| Name | Type | Description |
|---|---|---|
options | UsePrefetchQueryOptions<TQueryFnData, TError, TData, TQueryData, TQueryKey> | Options for the query; these are the options accepted by queryClient.query. queryKey is required, and queryFn is required unless a default query function exists. |
queryClient | QueryClient | undefined | Optional custom QueryClient. If omitted, the client from the nearest context is used. |
void; the hook does not return anything.
import { Suspense } from 'react'
import { usePrefetchQuery } from '@tanstack/react-query'
async function fetchPosts() {
const response = await fetch('/api/posts')
if (!response.ok) throw new Error('Request failed')
return response.json() as Promise<{ id: number; title: string }[]>
}
function App() {
usePrefetchQuery({
queryKey: ['posts'],
queryFn: fetchPosts,
})
return (
<Suspense fallback={<p>Loading posts...</p>}>
<Posts />
</Suspense>
)
}
function Posts() {
return <div>Posts render here</div>
}Call the hook during render before a Suspense boundary containing the component that will consume the prefetched query.
A page renders a Suspense-wrapped child that reads data with useSuspenseQuery.
A component knows the next query key and wants to populate the cache ahead of a descendant render.
An application has more than one QueryClient and needs this prefetch to target a specific one.
It initiates prefetching during render and returns void. Its intended placement is immediately before a Suspense boundary whose descendant uses useSuspenseQuery.
Follow-up: What happens when the query already has state? The prefetch is skipped, including when that state is pending or is an error from an earlier attempt.
The options argument contains everything accepted by queryClient.query. The queryKey is mandatory, and queryFn is mandatory unless a default query function is configured.
Follow-up: How can a different client be selected? Pass a QueryClient as the optional second argument; otherwise the nearest context client is used.
It returns nothing, so it is used for its prefetch side effect rather than for reading query data. A separate query hook reads the result after the prefetch has started or completed.
Follow-up: Why is calling it on every render acceptable? Cached or in-flight state causes the prefetch to be skipped instead of refetching that query.
useSuspenseQueryusePrefetchInfiniteQueryqueryClient.queryQueryClientUsePrefetchQueryOptions