占位查询数据
什么是占位数据?
占位数据(placeholder data)允许一个查询表现得如同它已经拥有数据一样,其效果类似于 initialData 选项,但该数据不会被持久化到缓存中。这在你已掌握足够多的局部(或模拟)数据、足以成功渲染查询结果,而真实数据仍在后台拉取的场景下非常有用。
示例:针对单篇博客文章的查询,可从父级博客文章列表中提取“预览”数据——该列表仅包含文章标题和正文的一小段摘要。你并不希望将此类局部数据持久化为该单篇文章查询的结果,但它确实有助于在真实查询完成并获取完整对象前,尽可能快地展示内容布局。
有几种方式可在你需要之前,向缓存中提供查询所需的占位数据:
- 声明式:
- 向查询提供
placeholderData,以便在缓存为空时预先填充其缓存
- 向查询提供
- 命令式:
当我们使用 placeholderData 时,查询将不会处于 pending 状态——它会直接以 success 状态启动,因为我们已有 data 可供展示——即使该数据仅为“占位”数据。为将其与“真实”数据区分开来,查询结果中的 isPlaceholderData 标志也将被设为 true。
占位数据作为值
1class TodosComponent {2 readonly todosQuery = injectQuery(() => ({3 queryKey: ['todos'],4 queryFn: () => fetch('/todos'),5 placeholderData: placeholderTodos,6 }))7}占位数据作为函数
placeholderData 还可以是一个函数,在其中你可以访问“上一次”成功查询的数据及查询元信息(Query meta information)。当你希望将一个查询的数据用作另一个查询的占位数据时,这种方式尤为有用。当查询键(QueryKey)发生变化(例如从 ['todos', 1] 变为 ['todos', 2])时,我们可以继续显示“旧”数据,而非在数据从一个查询过渡到下一个查询的过程中显示加载指示器。更多信息,请参阅 分页查询(Paginated Queries)。
1class TodosComponent {2 readonly todoQuery = injectQuery(() => ({3 queryKey: ['todos', id()],4 queryFn: () => fetch(`/todos/${id}`),5 placeholderData: (previousData, previousQuery) => previousData,6 }))7}来自缓存的占位数据
在某些情况下,你可能能够从另一查询的缓存结果中提供当前查询所需的占位数据。一个典型示例是:在博客文章列表查询的缓存数据中搜索某篇文章的预览版本,然后将该预览数据用作该文章单独查询的占位数据:
1export class BlogPostComponent {2 postId = input.required<number>()3 readonly queryClient = inject(QueryClient)4 5 readonly blogPostQuery = injectQuery(() => ({6 queryKey: ['blogPost', this.postId()],7 queryFn: () => fetch(`/blogPosts/${this.postId()}`),8 placeholderData: () => {9 // Use the smaller/preview version of the blogPost from the 'blogPosts'10 // query as the placeholder data for this blogPost query11 return this.queryClient12 .getQueryData(['blogPosts'])13 ?.find((d) => d.id === this.postId())14 },15 }))16}