使用TanStack React Query实现分页时按钮失效,无法获取新数据
问题分析与修复方案
你的代码主要存在以下几个问题导致分页切换时无法获取新数据:
1. prefetchQuery的queryFn调用错误
fetchData函数期望接收包含queryKey的对象参数,但你在预取数据时直接传入了页码数字,导致函数无法正确解析页码。应该直接传入fetchData函数,React Query会自动传递包含queryKey的参数。
2. 未开启keepPreviousData配置
默认情况下,当queryKey(页码)变化时,React Query会丢弃旧数据并进入加载状态,同时isPreviousData无法正确工作。开启keepPreviousData: true后,会在获取新数据时保留旧数据,确保分页切换的流畅性,同时isPreviousData会正确标识当前数据是否属于上一页。
3. hasMore判断逻辑错误
JSONPlaceholder返回的分页数据是纯数组,没有hasMore字段。你需要根据返回数据的长度判断是否还有下一页(该API默认每页返回10条数据,当返回数据长度小于10时说明已到最后一页)。
4. 下一页按钮逻辑失效
因为data?.hasMore始终为undefined,导致点击下一页时页码无法递增,需要先修复hasMore的判断逻辑。
修改后的完整代码
1. fetchData.js(无需修改)
export const fetchData = async ({queryKey}) => { const page = queryKey[1]; const res = await fetch( `https://jsonplaceholder.typicode.com/posts?_page=${page + 1}` ); return res.json(); }
2. App.js(修改核心逻辑)
import { useQueryClient, useQuery } from '@tanstack/react-query'; import { useState, useEffect } from 'react'; import { fetchData } from './components/fetchData'; function App() { const queryClient = useQueryClient(); const [page, setPage] = useState(0); const { isLoading, error, data, isFetching, isPreviousData } = useQuery({ queryKey: ["repoData", page], queryFn: fetchData, // 开启保留旧数据,确保分页切换流畅 keepPreviousData: true, }); // 计算是否还有下一页:JSONPlaceholder默认每页10条,长度等于10则还有下一页 const hasMore = data?.length === 10; useEffect(() => { // 当当前数据不是上一页的,且还有下一页时,预取下一页数据 if (!isPreviousData && hasMore) { queryClient.prefetchQuery({ queryKey: ['repoData', page + 1], // 直接传入fetchData,React Query会自动传递queryKey参数 queryFn: fetchData }) } },[data, isPreviousData, page, queryClient, hasMore]) if (isLoading) return "Loading..."; if (error) return "An error has occurred: " + error.message; return ( <div> {data.map((post) => ( <div key={post.id}> <h3>{post.title}</h3> <p>Post ID: {post.id}</p> </div> ))} <span>Current Page: {page + 1}</span> <button onClick={() => setPage((old) => Math.max(old - 1, 0))} disabled={page === 0} > Previous Page </button>{" "} <button onClick={() => { if (hasMore) { setPage(old => old + 1); } }} disabled={!hasMore} > Next Page </button> {isFetching ? <span> Loading...</span> : null}{" "} </div> ); } export default App;
额外说明
- 移除了无用的
ReactPaginate和Component1导入,避免代码冗余 - 修正了渲染数据时的错误:JSONPlaceholder的posts没有
completed字段,改成渲染post的id和title - 为按钮添加了合理的
disabled状态,提升用户体验
内容的提问来源于stack exchange,提问作者web_dev
相关产品推荐
相关产品推荐

