占位符查询数据

什么是占位符数据?

占位符数据允许查询在行为上如同已拥有数据一样,类似于 initialData 选项,但数据不会持久化到缓存中。这在您拥有足够的部分(或伪造)数据来成功渲染查询,同时在后台获取实际数据的情况下非常有用。

示例:单个博客文章查询可以从仅包含标题和帖子正文片段的父博客文章列表中拉取“预览”数据。您不会希望将此部分数据持久化到单个查询的结果缓存中,但它对于在实际查询完成并获取整个对象之前尽快显示内容布局非常有用。

有几种方法可以在需要之前为查询提供占位符数据到缓存中

当我们使用 placeholderData 时,我们的查询不会处于 pending 状态——它将最初处于 success 状态,因为我们有 data 可供显示——即使该数据只是“占位符”数据。为了区分它与“真实”数据,查询结果中还将设置 isPlaceholderData 标志为 true

作为值的占位符数据

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

作为函数的占位符数据

placeholderData 也可以是一个函数,您可以在其中访问“先前”成功查询的数据和 Query 元信息。这在您希望将一个查询的数据用作另一个查询的占位符数据的情况下非常有用。当 QueryKey 更改时,例如从 ['todos', 1] 更改为 ['todos', 2],我们可以继续显示“旧”数据,而无需显示加载微件,因为数据正在从一个查询“转换”到下一个查询。有关更多信息,请参阅 分页查询

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

来自缓存的占位符数据

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

tsx
const result = useQuery({
  queryKey: ['blogPost', blogPostId],
  queryFn: () => fetch(`/blogPosts/${blogPostId}`),
  placeholderData: () => {
    // Use the smaller/preview version of the blogPost from the 'blogPosts'
    // query as the placeholder data for this blogPost query
    return queryClient
      .getQueryData(['blogPosts'])
      ?.find((d) => d.id === blogPostId)
  },
})
const result = useQuery({
  queryKey: ['blogPost', blogPostId],
  queryFn: () => fetch(`/blogPosts/${blogPostId}`),
  placeholderData: () => {
    // Use the smaller/preview version of the blogPost from the 'blogPosts'
    // query as the placeholder data for this blogPost query
    return queryClient
      .getQueryData(['blogPosts'])
      ?.find((d) => d.id === blogPostId)
  },
})