占位符数据允许查询的行为就好像它已经有了数据,类似于 initialData 选项,但这些数据不会持久化到缓存中。当您有足够的局部(或模拟)数据来成功渲染查询,而实际数据在后台获取时,这会非常有用。
示例:单个博客文章查询可以从只包含标题和文章正文一小段内容的父博客文章列表中提取“预览”数据。您不希望将此局部数据持久化到单个查询的结果缓存中,但它有助于在实际查询完成以获取整个对象之前尽快显示内容布局。
有几种方法可以在需要之前为查询提供占位符数据到缓存中
当我们使用 placeholderData 时,我们的查询将不会处于 pending 状态——它将以 success 状态开始,因为我们有 data 可以显示——即使这些数据仅仅是“占位符”数据。为了将其与“真实”数据区分开来,查询结果上的 isPlaceholderData 标志也将设置为 true。
function Todos() {
const result = useQuery(() => {
queryKey: ['todos'],
queryFn: () => fetch('/todos'),
placeholderData: placeholderTodos,
})
}
function Todos() {
const result = useQuery(() => {
queryKey: ['todos'],
queryFn: () => fetch('/todos'),
placeholderData: placeholderTodos,
})
}
如果访问查询的占位符数据的过程很耗时,或者只是您不想在每次渲染时都执行的操作,您可以对该值进行记忆化处理
function Todos() {
const placeholderData = createMemo(() => generateFakeTodos(), [])
const result = useQuery(() => {
queryKey: ['todos'],
queryFn: () => fetch('/todos'),
placeholderData,
})
}
function Todos() {
const placeholderData = createMemo(() => generateFakeTodos(), [])
const result = useQuery(() => {
queryKey: ['todos'],
queryFn: () => fetch('/todos'),
placeholderData,
})
}
placeholderData 也可以是一个函数,您可以在其中访问“前一个”成功查询的数据和 Query 元信息。这在您希望使用一个查询的数据作为另一个查询的占位符数据的场景中非常有用。当 QueryKey 发生变化时,例如从 ['todos', 1] 变为 ['todos', 2],我们可以继续显示“旧”数据,而不是在数据从一个查询过渡到下一个查询时显示加载指示器。更多信息,请参阅 分页查询。
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,
})
在某些情况下,您可以为查询提供来自另一个查询的缓存结果的占位符数据。一个很好的例子是搜索博客文章列表查询的缓存数据,以获取文章的预览版本,然后将其作为单个文章查询的占位符数据
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)
},
})
}
有关 占位符数据 和 初始数据 的比较,请查看 社区资源。