占位查询数据

占位查询数据

什么是占位数据?

占位数据允许一个查询表现得好像它已经拥有数据,类似于 initialData 选项,但这些数据不会被持久化到缓存中。这在你拥有足够的部分(或模拟)数据来成功渲染查询,同时实际数据在后台获取的场景下非常有用。

示例:一个单独的博客文章查询可以从父级的博客文章列表中提取“预览”数据,该列表只包含标题和文章正文的一小段摘要。你可能不希望将这种部分数据持久化到该单独查询的结果缓存中,但它对于尽快展示内容布局非常有用,同时实际查询继续获取完整的对象。

有几种方式可以在需要之前为查询向缓存提供占位数据:

  • 声明式:

    • 为查询提供 placeholderData,如果缓存为空,则预填充其缓存

  • 命令式:

    • 使用 queryClientplaceholderData 选项预取或获取数据

当我们使用 placeholderData 时,我们的查询将不再处于 pending(加载中)状态——它会直接以 success(成功)状态开始,因为我们有数据可以显示——即使这些数据只是“占位”数据。为了将其与“真实”数据区分开来,查询结果上还会将 isPlaceholderData 标志设置为 true

将占位数据作为值使用

function Todos() {
  const result = useQuery({
    queryKey: ['todos'],
    queryFn: () => fetch('/todos'),
    placeholderData: placeholderTodos,
  })
}

占位数据的缓存(Memoization)

如果访问查询占位数据的过程很耗时,或者你不想在每次渲染时都执行,可以对值进行缓存:

function Todos() {
  const placeholderData = useMemo(() => generateFakeTodos(), [])
  const result = useQuery({
    queryKey: ['todos'],
    queryFn: () => fetch('/todos'),
    placeholderData,
  })
}

将占位数据作为函数使用

placeholderData 也可以是一个函数,在该函数中你可以访问“前一个”成功查询的数据和查询元信息。这在你想将一个查询的数据用作另一个查询的占位数据时非常有用。当查询键(QueryKey)发生变化时,例如从 ['todos', 1] 变为 ['todos', 2],我们可以继续显示“旧”数据,而不是在数据从一个查询过渡到下一个查询时显示加载动画。更多详细信息,请参阅 分页查询。

const result = useQuery({
  queryKey: ['todos', id],
  queryFn: () => fetch(`/todos/${id}`),
  placeholderData: (previousData, previousQuery) => previousData,
})

从缓存中获取占位数据

在某些情况下,你可以从另一个查询的缓存结果中提供查询的占位数据。一个很好的例子是:在博客文章列表查询的缓存数据中搜索某篇文章的预览版本,然后将其用作该文章单独查询的占位数据:

function Todo({ blogPostId }) {
  const queryClient = useQueryClient()
  const result = useQuery({
    queryKey: ['blogPost', blogPostId],
    queryFn: () => fetch(`/blogPosts/${blogPostId}`),
    placeholderData: () => {
      // 使用 'blogPosts' 查询中的较小/预览版本的博客文章
      // 作为此博客文章查询的占位数据
      return queryClient
        .getQueryData(['blogPosts'])
        ?.find((d) => d.id === blogPostId)
    },
  })
}

延伸阅读

如需比较 占位数据初始数据,请查看 社区资源。

最后更新于

这有帮助吗?