You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 08:54:58