框架
版本

占位符查询数据

什么是占位符数据?

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

示例:单个博客文章查询可以从父博客文章列表中提取“预览”数据,该列表只包含标题和文章正文的一小段摘录。您不希望将此部分数据持久化到单个查询的查询结果中,但它有助于尽快显示内容布局,同时实际查询完成以获取整个对象。

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

当我们使用 placeholderData 时,我们的查询将不会处于 pending 状态 - 它将以 success 状态开始,因为我们有 data 可供显示 - 即使这些数据只是“占位符”数据。为了将其与“真实”数据区分开来,查询结果中的 isPlaceholderData 标志也将设置为 true

作为值的占位符数据

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

占位符数据记忆

如果访问查询占位符数据的过程非常耗时,或者您不想在每次渲染时都执行此操作,您可以记忆化该值

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

作为函数的占位符数据

placeholderData 也可以是一个函数,您可以通过它访问“前一个”成功查询的数据和查询元信息。这在您希望使用一个查询的数据作为另一个查询的占位符数据的情况下非常有用。当 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
function Todo({ blogPostId }) {
  const queryClient = useQueryClient()
  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)
    },
  })
}
function Todo({ blogPostId }) {
  const queryClient = useQueryClient()
  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)
    },
  })
}

延伸阅读

有关 Placeholder DataInitial Data 的比较,请查看社区资源