File: react-query-queued-prefetch.md | Updated: 11/15/2025
Search...
+ K
Auto
Docs Examples GitHub Contributors
Docs Examples GitHub Contributors
Docs Examples GitHub Contributors
Docs Examples Github Contributors
Docs Examples Github Contributors
Docs Examples Github Contributors
Docs Examples Github Contributors
Docs Examples Github Contributors
Maintainers Partners Support Learn StatsBETA Discord Merch Blog GitHub Ethos Brand Guide
Documentation
Framework
React
Version
Latest
Search...
+ K
Menu
Getting Started
Guides
API Reference
Debouncer API Reference
Throttler API Reference
Rate Limiter API Reference
Queue API Reference
Batcher API Reference
Debouncer Examples
Throttler Examples
Rate Limiter Examples
Queue Examples
Batcher Examples
TanStack Query Examples
Framework
React
Version
Latest
Menu
Getting Started
Guides
API Reference
Debouncer API Reference
Throttler API Reference
Rate Limiter API Reference
Queue API Reference
Batcher API Reference
Debouncer Examples
Throttler Examples
Rate Limiter Examples
Queue Examples
Batcher Examples
TanStack Query Examples
React Example: React Query Queued Prefetch
=====================================================================================================================================================================================================================================================================================================================================================================================================================================================================================
Code ExplorerCode
Interactive SandboxSandbox
public
src
.eslintrc.cjs
.gitignore
README.md
index.html
package.json
tsconfig.json
vite.config.ts
tsx
import React, { useEffect } from 'react'
import ReactDOM from 'react-dom/client'
import {
QueryClient,
QueryClientProvider,
useQuery,
} from '@tanstack/react-query'
import { ReactQueryDevtools } from '@tanstack/react-query-devtools'
import { useQueuedValue } from '@tanstack/react-pacer'
// Fetch all posts
const fetchPosts = async () => {
const response = await fetch('https://jsonplaceholder.typicode.com/posts')
return response.json()
}
// Fetch a single post
const fetchPost = async (id: number) => {
await new Promise((resolve) => setTimeout(resolve, 500)) // Simulate a slow response
const response = await fetch(
`https://jsonplaceholder.typicode.com/posts/${id}`,
)
return response.json()
}
function PostList({
setSelectedPostId,
}: {
setSelectedPostId: (id: number) => void
}) {
// Simple query that fetches all posts
const { data: posts, isLoading } = useQuery({
queryKey: ['posts'],
queryFn: fetchPosts,
})
// keep track of the hovered post id that could be prefetched
const [currentHoveredPostId, setCurrentHoveredPostId] = React.useState<
number | null
>(null)
const [queuedHoveredPostId] = useQueuedValue(currentHoveredPostId, {
addItemsTo: 'front', // newest hovered link is top priority
wait: 100, // adjust this value to see the difference
expirationDuration: 500, // If a link was hovered over 500ms ago, and still hasn't been prefetched, remove it from the queue
onExpire: (item) => {
console.log('expired', item)
},
})
useEffect(() => {
if (queuedHoveredPostId) {
// queue up the hovered post id to be processed in order
queryClient.ensureQueryData({
queryKey: ['post', queuedHoveredPostId],
queryFn: () => fetchPost(queuedHoveredPostId),
})
}
}, [queuedHoveredPostId])
const handleMouseEnter = (postId: number) => {
setCurrentHoveredPostId(postId) // update the hovered post id
}
if (isLoading) return <div>Loading posts...</div>
return (
<div>
<h2>Posts</h2>
<ul style={{ margin: 0, padding: 0 }}>
{posts?.map((post: { id: number; title: string }) => (
<li key={post.id} style={{ margin: '2px 0' }}>
<a
href={`#post-${post.id}`}
onMouseEnter={() => handleMouseEnter(post.id)}
onClick={() => setSelectedPostId(post.id)}
style={{ display: 'block', padding: '4px', cursor: 'pointer' }}
>
{post.title}
</a>
</li>
))}
</ul>
</div>
)
}
function PostDetail({ postId }: { postId: number }) {
const { data: post, isLoading } = useQuery({
queryKey: ['post', postId],
queryFn: () => fetchPost(postId),
})
if (isLoading) return <div>Loading post...</div>
return (
<div>
<h3>{post?.title}</h3>
<p>{post?.body}</p>
</div>
)
}
function App() {
const [selectedPostId, setSelectedPostId] = React.useState<number | null>(
null,
)
return (
<div
className="App"
style={{ maxWidth: '800px', margin: '0 auto', padding: '20px' }}
>
<h1>TanStack Pacer/Query Queued Prefetch Example</h1>
<p>Hover over a post title to queue up its prefetch</p>
<p>
This example shows how to queue up prefetch requests when the user
hovers over a post, processing them in order with a delay between each.
</p>
<p>
The queued query key is processed after a delay to avoid overwhelming
the server with too many requests at once.
</p>
<div
style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '20px' }}
>
<PostList setSelectedPostId={setSelectedPostId} />
{selectedPostId && <PostDetail postId={selectedPostId} />}
</div>
</div>
)
}
const queryClient = new QueryClient({
defaultOptions: {
queries: {
staleTime: 10_000,
},
},
})
const root = ReactDOM.createRoot(document.getElementById('root')!)
root.render(
<QueryClientProvider client={queryClient}>
<App />
<ReactQueryDevtools initialIsOpen={false} />
</QueryClientProvider>,
)
import React, { useEffect } from 'react'
import ReactDOM from 'react-dom/client'
import {
QueryClient,
QueryClientProvider,
useQuery,
} from '@tanstack/react-query'
import { ReactQueryDevtools } from '@tanstack/react-query-devtools'
import { useQueuedValue } from '@tanstack/react-pacer'
// Fetch all posts
const fetchPosts = async () => {
const response = await fetch('https://jsonplaceholder.typicode.com/posts')
return response.json()
}
// Fetch a single post
const fetchPost = async (id: number) => {
await new Promise((resolve) => setTimeout(resolve, 500)) // Simulate a slow response
const response = await fetch(
`https://jsonplaceholder.typicode.com/posts/${id}`,
)
return response.json()
}
function PostList({
setSelectedPostId,
}: {
setSelectedPostId: (id: number) => void
}) {
// Simple query that fetches all posts
const { data: posts, isLoading } = useQuery({
queryKey: ['posts'],
queryFn: fetchPosts,
})
// keep track of the hovered post id that could be prefetched
const [currentHoveredPostId, setCurrentHoveredPostId] = React.useState<
number | null
>(null)
const [queuedHoveredPostId] = useQueuedValue(currentHoveredPostId, {
addItemsTo: 'front', // newest hovered link is top priority
wait: 100, // adjust this value to see the difference
expirationDuration: 500, // If a link was hovered over 500ms ago, and still hasn't been prefetched, remove it from the queue
onExpire: (item) => {
console.log('expired', item)
},
})
useEffect(() => {
if (queuedHoveredPostId) {
// queue up the hovered post id to be processed in order
queryClient.ensureQueryData({
queryKey: ['post', queuedHoveredPostId],
queryFn: () => fetchPost(queuedHoveredPostId),
})
}
}, [queuedHoveredPostId])
const handleMouseEnter = (postId: number) => {
setCurrentHoveredPostId(postId) // update the hovered post id
}
if (isLoading) return <div>Loading posts...</div>
return (
<div>
<h2>Posts</h2>
<ul style={{ margin: 0, padding: 0 }}>
{posts?.map((post: { id: number; title: string }) => (
<li key={post.id} style={{ margin: '2px 0' }}>
<a
href={`#post-${post.id}`}
onMouseEnter={() => handleMouseEnter(post.id)}
onClick={() => setSelectedPostId(post.id)}
style={{ display: 'block', padding: '4px', cursor: 'pointer' }}
>
{post.title}
</a>
</li>
))}
</ul>
</div>
)
}
function PostDetail({ postId }: { postId: number }) {
const { data: post, isLoading } = useQuery({
queryKey: ['post', postId],
queryFn: () => fetchPost(postId),
})
if (isLoading) return <div>Loading post...</div>
return (
<div>
<h3>{post?.title}</h3>
<p>{post?.body}</p>
</div>
)
}
function App() {
const [selectedPostId, setSelectedPostId] = React.useState<number | null>(
null,
)
return (
<div
className="App"
style={{ maxWidth: '800px', margin: '0 auto', padding: '20px' }}
>
<h1>TanStack Pacer/Query Queued Prefetch Example</h1>
<p>Hover over a post title to queue up its prefetch</p>
<p>
This example shows how to queue up prefetch requests when the user
hovers over a post, processing them in order with a delay between each.
</p>
<p>
The queued query key is processed after a delay to avoid overwhelming
the server with too many requests at once.
</p>
<div
style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '20px' }}
>
<PostList setSelectedPostId={setSelectedPostId} />
{selectedPostId && <PostDetail postId={selectedPostId} />}
</div>
</div>
)
}
const queryClient = new QueryClient({
defaultOptions: {
queries: {
staleTime: 10_000,
},
},
})
const root = ReactDOM.createRoot(document.getElementById('root')!)
root.render(
<QueryClientProvider client={queryClient}>
<App />
<ReactQueryDevtools initialIsOpen={false} />
</QueryClientProvider>,
)
React Query Throttled Prefetch
