译零 TransZero · TanStack Query 中文文档
主站

分页查询 / 滞后查询

更新于 2026-11-02 React 查看英文原文 ↗

渲染分页数据是一种非常常见的 UI 模式,在 TanStack Query 中,只需将页码信息包含在查询键(query key)中,该模式便“开箱即用”:

TypeScript
1const result = useQuery({2  queryKey: ['projects', page],3  queryFn: () => fetchProjects(page),4})

然而,如果你运行这个简单示例,可能会注意到一个奇怪的现象:

UI 会在 success 和 pending 状态之间反复跳动,因为每个新页面都被视为一个全新的查询。

这种体验并不理想,不幸的是,当前许多工具仍坚持如此工作。但 TanStack Query 并非如此!你可能已经猜到,TanStack Query 提供了一个名为 placeholderData 的强大功能,可帮助我们规避这一问题。

使用 placeholderData 实现更优的分页查询

考虑以下示例:我们理想情况下希望为某个查询递增 pageIndex(或游标)。若仅使用 useQuery,技术上依然可以正常工作,但每当为不同页面或游标创建并销毁新查询时,UI 仍会在 success 和 pending 状态之间跳动。通过将 placeholderData 设为 (previousData) => previousData 或 keepPreviousData(TanStack Query 导出的函数),你将获得以下几项新能力:

  • 即使查询键已变更,上一次成功拉取的数据仍可用,直至新数据请求完成。
  • 当新数据到达时,先前的 data 会被无缝切换为新数据。
  • isPlaceholderData 可用于获知当前查询实际提供给你的数据是哪一份。
TypeScript
1import { keepPreviousData, useQuery } from '@tanstack/react-query'2import React from 'react'3 4function Todos() {5  const [page, setPage] = React.useState(0)6 7  const fetchProjects = (page = 0) =>8    fetch('/api/projects?page=' + page).then((res) => res.json())9 10  const { isPending, isError, error, data, isFetching, isPlaceholderData } =11    useQuery({12      queryKey: ['projects', page],13      queryFn: () => fetchProjects(page),14      placeholderData: keepPreviousData,15    })16 17  return (18    <div>19      {isPending ? (20        <div>Loading...</div>21      ) : isError ? (22        <div>Error: {error.message}</div>23      ) : (24        <div>25          {data.projects.map((project) => (26            <p key={project.id}>{project.name}</p>27          ))}28        </div>29      )}30      <span>Current Page: {page + 1}</span>31      <button32        onClick={() => setPage((old) => Math.max(old - 1, 0))}33        disabled={page === 0}34      >35        Previous Page36      </button>37      <button38        onClick={() => {39          if (!isPlaceholderData && data.hasMore) {40            setPage((old) => old + 1)41          }42        }}43        // Disable the Next Page button until we know a next page is available44        disabled={isPlaceholderData || !data?.hasMore}45      >46        Next Page47      </button>48      {isFetching ? <span> Loading...</span> : null}49    </div>50  )51}

使用 placeholderData 对无限查询(infinite query)结果进行滞后处理

尽管使用频率较低,placeholderData 选项同样能与 useInfiniteQuery Hook 完美配合,使用户在无限查询键(infinite query keys)随时间变化的过程中,持续无缝地看到缓存数据。

本页为 TanStack Query 文档(React 版)的非官方中文翻译,原文由上游团队维护,遵循 MIT 许可。 译文如有偏差,以英文原文为准。

译自上游 59d11de