分页查询
分页查询 / 延迟查询
渲染分页数据是一种非常常见的 UI 模式。在 TanStack Query 中,只需将页面信息包含在查询键(query key)中,它就能“正常工作”:
const result = useQuery({
queryKey: ['projects', page],
queryFn: fetchProjects,
})然而,如果你运行这个简单的示例,可能会注意到一个奇怪的现象:
UI 会在 success(成功)和 pending(加载中)状态之间来回跳动,因为每个新页面都被视为一个全新的查询。
这种体验并不理想,不幸的是,这正是许多工具目前的工作方式。但 TanStack Query 不会如此!正如你可能猜到的,TanStack Query 提供了一个名为 placeholderData 的强大功能,可以解决这个问题。
使用 placeholderData 实现更优的分页查询
placeholderData 实现更优的分页查询考虑以下示例,我们理想情况下希望为查询递增一个 pageIndex(或游标)。如果我们使用 useQuery,技术上它仍然可以正常工作,但 UI 会随着不同页面或游标创建和销毁不同的查询而在 success 和 pending 状态之间跳动。通过将 placeholderData 设置为 (previousData) => previousData 或使用 TanStack Query 导出的 keepPreviousData 函数,我们可以获得以下优势:
即使查询键已更改,在请求新数据时,上一次成功获取的数据仍然可用。
当新数据到达时,旧的
data会无缝切换为新数据。提供了
isPlaceholderData标志,用于判断当前查询返回的数据是否为占位数据。
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>加载中...</div>
) : isError ? (
<div>错误: {error.message}</div>
) : (
<div>
{data.projects.map((project) => (
<p key={project.id}>{project.name}</p>
))}
</div>
)}
<span>当前页码: {page + 1}</span>
<button
onClick={() => setPage((old) => Math.max(old - 1, 0))}
disabled={page === 0}
>
上一页
</button>
<button
onClick={() => {
if (!isPlaceholderData && data.hasMore) {
setPage((old) => old + 1)
}
}}
// 在确认有下一页之前禁用“下一页”按钮
disabled={isPlaceholderData || !data?.hasMore}
>
下一页
</button>
{isFetching ? <span> 加载中...</span> : null}
</div>
)
}使用 placeholderData 延迟无限查询结果
placeholderData 延迟无限查询结果虽然这种情况不太常见,但 placeholderData 选项与 useInfiniteQuery Hook 也能完美配合,让你的用户在无限查询的键随时间变化时,依然能够无缝地看到缓存的数据。
最后更新于
这有帮助吗?