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

分页查询 / 滞后查询

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

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

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

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

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

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

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

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

  • 即使查询键(query key)已变更,在新数据被拉取期间,上一次成功拉取的数据依然可用。
  • 当新数据到达时,先前的 data 会被无缝切换以展示新数据。
  • isPlaceholderData 可供你获知当前查询实际提供的是哪部分数据。
TypeScript
1import { createSignal, Switch, Match, Show, For } from 'solid-js'2import { keepPreviousData, useQuery } from '@tanstack/solid-query'3 4function Todos() {5  const [page, setPage] = createSignal(0)6 7  const fetchProjects = (page = 0) =>8    fetch('/api/projects?page=' + page).then((res) => res.json())9 10  const projectsQuery = useQuery(() => ({11    queryKey: ['projects', page()],12    queryFn: () => fetchProjects(page()),13    placeholderData: keepPreviousData,14  }))15 16  return (17    <div>18      <Switch>19        <Match when={projectsQuery.isPending}>20          <div>Loading...</div>21        </Match>22        <Match when={projectsQuery.isError}>23          <div>Error: {projectsQuery.error.message}</div>24        </Match>25        <Match when={projectsQuery.isSuccess}>26          <div>27            <For each={projectsQuery.data.projects}>28              {(project) => <p>{project.name}</p>}29            </For>30          </div>31        </Match>32      </Switch>33      <span>Current Page: {page() + 1}</span>34      <button35        onClick={() => setPage((old) => Math.max(old - 1, 0))}36        disabled={page() === 0}37      >38        Previous Page39      </button>40      <button41        onClick={() => {42          if (!projectsQuery.isPlaceholderData && projectsQuery.data?.hasMore) {43            setPage((old) => old + 1)44          }45        }}46        // Disable the Next Page button until we know a next page is available47        disabled={48          projectsQuery.isPlaceholderData || !projectsQuery.data?.hasMore49        }50      >51        Next Page52      </button>53      <Show when={projectsQuery.isFetching}>54        <span> Loading...</span>55      </Show>56    </div>57  )58}

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

尽管使用频率较低,placeholderData 选项与 useInfiniteQuery 原语配合也完全无误,因此你可以让用户在无限查询键(infinite query keys)随时间变化的同时,持续看到缓存的数据。

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

译自上游 59d11de