Link prefetching using react-query

Today we will see how to implement link prefetching and caching queries using React-query We’ll start with a simple article app, which will list a number of articles, and after clicking on each link will open the Here’s the starting app import'./App.css'import React from'react'import{useQuery}from'react-query'import{ReactQueryDevtools}from'react-query-devtools'import axios from'axios'constPOSTS='https://jsonplaceholder.typicode.com/posts'functionPost({postId, setPostId}){const postQuery =useQuery(['post', postId],()=> axios .get(`${POSTS}/${postId}`).then(res=> res.data))return(<div className='post'><div>{ postQuery.isLoading

Today we will see how to implement link prefetching and caching queries using React-query

We’ll start with a simple article app, which will list a number of articles, and after clicking on each link will open the

Here’s the starting app

import'./App.css'import React from'react'import{useQuery}from'react-query'import{ReactQueryDevtools}from'react-query-devtools'import axios from'axios'constPOSTS='https://jsonplaceholder.typicode.com/posts'functionPost({postId, setPostId}){const postQuery =useQuery(['post', postId],()=>
    axios
      .get(`${POSTS}/${postId}`).then(res=> res.data))return(<div className='post'><div>{
            postQuery.isLoading ?'Loading...':(<div><h2>{postQuery.data.title}</h2><div>{postQuery.data.body}</div></div>)}</div><button className='back' onClick={()=>setPostId(-1)}>Back</button></div>)}functionPosts({setPostId}){const postsQuery =useQuery('posts',async()=>
    axios
      .get(POSTS).then(res=> res.data))return(<div><h1>Posts</h1><div>{
          postsQuery.isLoading ?'Loading...':(<ul>{postsQuery.data.map(post=>{return(<li key={post.id} className='posts'><a onClick={()=>setPostId(post.id)} href='#'>{post.title}</a></li>)})}</ul>)}</div></div>)}functionApp(){const[postId, setPostId]= React.useState(-1)return(<div className="App">{
        postId >-1?(<Post postId={postId} setPostId={setPostId}/>):(<Posts setPostId={setPostId}/>)}<ReactQueryDevtools /></div>);}exportdefault App;

How it works is, when postId is set to -1, we’ll render the posts#index
and when we click on any post, we set the postId to the post.id, and we render the post/:id

{
  postId >-1?(<Post postId={postId} setPostId={setPostId}/>):(<Posts setPostId={setPostId}/>)}

The ReactQueryDevtools component is there to help us debug and understand the flow more easily.

By default, react-query will cache any request it fetches, and render it from cache next time when it’s needed, while trying to check if data needs to be refreshed. Let’s inspect that on the ReactQueryDevtools

We can make it even faster by introducing link-prefetching (fetch data when hovered on one link)

So, let’s extract the getPost function to keep our code clean.

asyncfunctiongetPost(postId){return axios
      .get(`${POSTS}/${postId}`).then(res=> res.data)}

and change our Post function to

functionPost({postId, setPostId}){const postQuery =useQuery(['post', postId],()=>getPost(postId))return(<div className='post'><div>{
            postQuery.isLoading ?'Loading...':(<div><h2>{postQuery.data.title}</h2><div>{postQuery.data.body}</div></div>)}</div><button className='back' onClick={()=>setPostId(-1)}>Back</button></div>)}

And add the Posts function to

import{useQuery, queryCache}from'react-query'functionPosts({setPostId}){const postsQuery =useQuery('posts',async()=>
    axios
      .get(POSTS).then(res=> res.data))return(<div><h1>Posts</h1><div>{
          postsQuery.isLoading ?'Loading...':(<ul>{postsQuery.data.map(post=>{return(<li key={post.id} className='posts'
                    onMouseEnter={()=> queryCache.prefetchQuery(['post', post.id],()=>getPost(post.id))}><a onClick={()=>setPostId(post.id)} href='#'>{post.title}</a></li>)})}</ul>)}</div></div>)}

Now prefetching should be working

Final code

import'./App.css'import React from'react'import{useQuery, queryCache}from'react-query'import{ReactQueryDevtools}from'react-query-devtools'import axios from'axios'constPOSTS='https://jsonplaceholder.typicode.com/posts'asyncfunctiongetPost(postId){return axios
      .get(`${POSTS}/${postId}`).then(res=> res.data)}functionPost({postId, setPostId}){const postQuery =useQuery(['post', postId],()=>getPost(postId))return(<div className='post'><div>{
            postQuery.isLoading ?'Loading...':(<div><h2>{postQuery.data.title}</h2><div>{postQuery.data.body}</div></div>)}</div><button className='back' onClick={()=>setPostId(-1)}>Back</button></div>)}functionPosts({setPostId}){const postsQuery =useQuery('posts',async()=>
    axios
      .get(POSTS).then(res=> res.data))return(<div><h1>Posts</h1><div>{
          postsQuery.isLoading ?'Loading...':(<ul>{postsQuery.data.map(post=>{return(<li key={post.id} className='posts' onMouseEnter={()=> queryCache.prefetchQuery(['post', post.id],()=>getPost(post.id))}><a onClick={()=>setPostId(post.id)} href='#'>{post.title}</a></li>)})}</ul>)}</div></div>)}functionApp(){const[postId, setPostId]= React.useState(-1)return(<div className="App">{
        postId >-1?(<Post postId={postId} setPostId={setPostId}/>):(<Posts setPostId={setPostId}/>)}<ReactQueryDevtools /></div>);}exportdefault App;

Nguồn: viblo.asia

Bài viết liên quan

9 Mẹo lập trình Web “ẩn mình” giúp tiết kiệm hàng giờ đồng hồ

Hầu hết các lập trình viên (kể cả những người giỏi) đều tốn thời gian x

Can GPT-4o Generate Images? All You Need to Know about GPT-4o-image

OpenAI‘s GPT-4o, introduced on March 25, 2025, has revolutionized the way we create visual con

Khi nào nên dùng main, section, article, header, footer, và aside trong HTML5

HTML5 đã giới thiệu các thẻ ngữ nghĩa giúp cấu trúc nội dung web một cách có

So sánh Webhook và API: Khi nào nên sử dụng?

Trong lĩnh vực công nghệ thông tin và phát triển phần mềm, Webhook và API là hai th