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 { useThrottledValue } 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, 1000)) // 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) // throttle the hovered post id to avoid excessive prefetches const [throttledHoveredPostId] = useThrottledValue(currentHoveredPostId, { wait: 100, // adjust this value to see the difference }) // perform the prefetch when the throttled hovered post id changes useEffect(() => { if (throttledHoveredPostId) { queryClient.ensureQueryData({ queryKey: ['post', throttledHoveredPostId], queryFn: () => fetchPost(throttledHoveredPostId), }) } }, [throttledHoveredPostId]) 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 Throttled Prefetch Example</h1> <p>Hover over a post title to prefetch its content</p> <p> This example shows how to prefetch a query when the user hovers over a post. </p> <p> The throttled query key is created after a throttle to avoid excessive prefetches. </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 { useThrottledValue } 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, 1000)) // 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) // throttle the hovered post id to avoid excessive prefetches const [throttledHoveredPostId] = useThrottledValue(currentHoveredPostId, { wait: 100, // adjust this value to see the difference }) // perform the prefetch when the throttled hovered post id changes useEffect(() => { if (throttledHoveredPostId) { queryClient.ensureQueryData({ queryKey: ['post', throttledHoveredPostId], queryFn: () => fetchPost(throttledHoveredPostId), }) } }, [throttledHoveredPostId]) 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 Throttled Prefetch Example</h1> <p>Hover over a post title to prefetch its content</p> <p> This example shows how to prefetch a query when the user hovers over a post. </p> <p> The throttled query key is created after a throttle to avoid excessive prefetches. </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>, )
Your weekly dose of JavaScript news. Delivered every Monday to over 100,000 devs, for free.
Your weekly dose of JavaScript news. Delivered every Monday to over 100,000 devs, for free.