分页查询

在 TanStack Query 中,渲染分页数据是一个非常常见的 UI 模式。通过将页面信息包含在查询键中,分页查询“即插即用”:

示例:分页查询

const result = useQuery({
  queryKey: ["projects", page],
  queryFn: fetchProjects
});

然而,您可能会注意到,如果您运行这个简单的示例,UI 会在成功 (success) 和挂起 (pending) 状态之间跳动,因为每一页都会被当作一个全新的查询处理。这种体验并不理想。

更好的分页查询:使用 placeholderData

TanStack Query 提供了一个非常有用的功能——placeholderData,可以避免分页查询过程中 UI 状态的跳跃。通过将 placeholderData 设置为 keepPreviousData,可以实现以下几点:

  1. 即使查询键发生变化,上一轮成功获取的数据依然会在新的数据请求过程中显示。

  2. 新的数据到达时,旧的数据会被无缝地替换,以展示最新的数据。

  3. isPlaceholderData 属性可以用来判断查询当前提供的数据是否是占位数据。

示例:使用 placeholderData 改进分页查询

import { keepPreviousData, useQuery } from "@tanstack/react-query";
import React from "react";

function Todos() {
  const [page, setPage] = React.useState(0);

  const fetchProjects = (page = 0) => fetch("/api/projects?page=" + page).then((res) => res.json());

  const { isPending, isError, error, data, isFetching, isPlaceholderData } = useQuery({
    queryKey: ["projects", page],
    queryFn: () => fetchProjects(page),
    placeholderData: keepPreviousData
  });

  return (
    <div>
      {isPending ? (
        <div>Loading...</div>
      ) : isError ? (
        <div>Error: {error.message}</div>
      ) : (
        <div>
          {data.projects.map((project) => (
            <p key={project.id}>{project.name}</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 (!isPlaceholderData && data.hasMore) {
            setPage((old) => old + 1);
          }
        }}
        // 禁用 “下一页” 按钮,直到知道是否有下一页
        disabled={isPlaceholderData || !data?.hasMore}
      >
        Next Page
      </button>
      {isFetching ? <span> Loading...</span> : null}
    </div>
  );
}

在这个例子中,placeholderData 使得即使在数据加载过程中,前一页的数据仍然可以显示,避免了 UI 状态的跳动。

使用 placeholderData 处理延迟的无限查询结果

虽然分页查询中更常见,但 placeholderData 选项在使用 useInfiniteQuery 钩子时也同样表现得非常好。您可以允许用户继续看到缓存数据,同时随着无限查询键的变化,数据会持续加载。

这种方法在大规模数据加载或需要无缝用户体验的应用程序中非常有用。

最后更新于

这有帮助吗?