patterntypescriptreactTip
TanStack Query — prefetching data before navigation
Viewed 0 times
prefetchQueryprefetchcache warmingnavigationhover prefetchrouter loaderstaleTime
Problem
When a user navigates to a detail page, useQuery starts fetching only after the component mounts, causing a loading flash. Prefetching loads data into the cache before navigation so the page renders immediately.
Solution
Call queryClient.prefetchQuery on hover or during parent render to warm the cache:
import { useQueryClient } from '@tanstack/react-query';
// Option 1: prefetch on link hover
function PostLink({ post }: { post: PostSummary }) {
const queryClient = useQueryClient();
const prefetch = () => {
queryClient.prefetchQuery({
queryKey: ['posts', post.id],
queryFn: () => fetchPostById(post.id),
staleTime: 1000 * 60, // reuse if already fresh
});
};
return (
<a href={
{post.title}
</a>
);
}
// Option 2: prefetch in React Router loader
export async function postLoader({ params }: LoaderFunctionArgs) {
await queryClient.prefetchQuery({
queryKey: ['posts', Number(params.id)],
queryFn: () => fetchPostById(Number(params.id)),
});
return null; // component's useQuery reads from cache
}
import { useQueryClient } from '@tanstack/react-query';
// Option 1: prefetch on link hover
function PostLink({ post }: { post: PostSummary }) {
const queryClient = useQueryClient();
const prefetch = () => {
queryClient.prefetchQuery({
queryKey: ['posts', post.id],
queryFn: () => fetchPostById(post.id),
staleTime: 1000 * 60, // reuse if already fresh
});
};
return (
<a href={
/posts/${post.id}} onMouseEnter={prefetch} onFocus={prefetch}>{post.title}
</a>
);
}
// Option 2: prefetch in React Router loader
export async function postLoader({ params }: LoaderFunctionArgs) {
await queryClient.prefetchQuery({
queryKey: ['posts', Number(params.id)],
queryFn: () => fetchPostById(Number(params.id)),
});
return null; // component's useQuery reads from cache
}
Why
prefetchQuery populates the cache without subscribing to it. When the component mounts and calls useQuery with the same key, the data is already present and returned synchronously, eliminating the loading state.
Gotchas
- prefetchQuery does nothing if a fresh entry already exists in the cache — safe to call multiple times
- Without staleTime, data prefetched more than 0ms ago is considered stale and will be refetched when the component mounts
- prefetchQuery does not return data — it is fire-and-forget for cache warming
- For SSR with Next.js App Router, use HydrationBoundary and dehydrate/hydrate instead of prefetchQuery
Revisions (0)
No revisions yet.