译零 TransZero · TanStack Query 中文文档
主站

初始查询数据

更新于 2026-11-02 Angular 查看英文原文 ↗

在需要之前,有多种方式可将初始数据提供给查询的缓存:

使用 initialData 预填充查询

有时你已在应用中拥有某个查询的初始数据,可直接将其提供给查询。若确实如此,你可使用 config.initialData 选项来设置查询的初始数据,并跳过初始加载状态!

重要:initialData 会被持久化到缓存中,因此不建议为此选项提供占位数据、部分数据或不完整数据;而应改用 placeholderData

TypeScript
1todosQuery = injectQuery(() => ({2  queryKey: ['todos'],3  queryFn: () => fetch('/todos'),4  initialData: initialTodos,5}))

staleTime 和 initialDataUpdatedAt

默认情况下,initialData 被视为完全新鲜的数据,如同刚刚拉取的一样。这也意味着它会影响 staleTime 选项对其的解释方式。

  • 若你为查询观察者配置了 initialData,但未配置 staleTime(即采用默认 staleTime: 0),则查询会立即重新拉取:

TypeScript
1// Will show initialTodos immediately, but also immediately refetch todos2// when an instance of the component or service is created3todosQuery = injectQuery(() => ({4  queryKey: ['todos'],5  queryFn: () => fetch('/todos'),6  initialData: initialTodos,7}))
  • 若你为查询观察者配置了 initialData 和 staleTime 值为 1000 ms,则该数据在此时间段内均被视为新鲜数据,如同刚从查询函数拉取的一样。

TypeScript
1// Show initialTodos immediately, but won't refetch until2// another interaction event is encountered after 1000 ms3todosQuery = injectQuery(() => ({4  queryKey: ['todos'],5  queryFn: () => fetch('/todos'),6  initialData: initialTodos,7  staleTime: 1000,8}))
  • 那么,若你的 initialData 并非完全新鲜呢?这就引出了最后一种配置方式——实际上也是最准确的方式,它使用一个名为 initialDataUpdatedAt 的选项。该选项允许你传入一个以毫秒为单位的 JavaScript 时间戳,表示初始数据本身最后一次更新的时间,例如 Date.now() 所提供的值。请注意,若你拥有 Unix 时间戳,则需将其乘以 1000 转换为 JavaScript 时间戳。

TypeScript
1// Show initialTodos immediately, but won't refetch until2// another interaction event is encountered after 1000 ms3todosQuery = injectQuery(() => ({4  queryKey: ['todos'],5  queryFn: () => fetch('/todos'),6  initialData: initialTodos,7  staleTime: 60 * 1000, // 1 minute8  // This could be 10 seconds ago or 10 minutes ago9  initialDataUpdatedAt: initialTodosUpdatedTimestamp, // eg. 160841242005210}))

此选项使 staleTime 可用于其原始目的——确定数据需保持多新鲜;同时,若 initialData 的更新时间早于 staleTime 所定义的时限,查询仍可在初始化时重新拉取数据。在上述示例中,我们的数据需在一分钟内保持新鲜,且我们可向查询提示初始数据最后一次更新的时间,从而让查询自行判断是否需要再次重新拉取。

若你更倾向于将数据视为预取数据,我们建议你提前使用 query API 填充缓存,从而让你能独立于 initialData 来配置 staleTime。

初始数据函数

若获取查询初始数据的过程开销较大,或你不希望每次服务或组件实例化时都执行该过程,你可以将一个函数作为 initialData 的值传入。该函数仅在查询初始化时执行一次,从而节省宝贵的内存和/或 CPU 资源:

TypeScript
1todosQuery = injectQuery(() => ({2  queryKey: ['todos'],3  queryFn: () => fetch('/todos'),4  initialData: () => getExpensiveTodos(),5}))

来自缓存的初始数据

在某些情况下,你可能能够从另一查询的缓存结果中获取某查询的初始数据。一个典型示例是:在待办事项列表查询的缓存数据中搜索某个单独的待办事项,再将该结果用作单独待办事项查询的初始数据:

TypeScript
1todoQuery = injectQuery(() => ({2  queryKey: ['todo', this.todoId()],3  queryFn: () => fetch('/todos'),4  initialData: () => {5    // Use a todo from the 'todos' query as the initial data for this todo query6    return this.queryClient7      .getQueryData(['todos'])8      ?.find((d) => d.id === this.todoId())9  },10}))

使用 initialDataUpdatedAt 从缓存获取初始数据

从缓存获取初始数据意味着你所使用的源查询很可能已过期。与其使用人为设定的 staleTime 来阻止查询立即重新拉取,不如将源查询的 dataUpdatedAt 传递给 initialDataUpdatedAt。这可为查询实例提供全部必要信息,使其能自主判断是否以及何时需要重新拉取,无论是否提供了初始数据。

TypeScript
1todoQuery = injectQuery(() => ({2  queryKey: ['todos', this.todoId()],3  queryFn: () => fetch(`/todos/${this.todoId()}`),4  initialData: () =>5    queryClient.getQueryData(['todos'])?.find((d) => d.id === this.todoId()),6  initialDataUpdatedAt: () =>7    queryClient.getQueryState(['todos'])?.dataUpdatedAt,8}))

条件性地从缓存获取初始数据

若你所使用的源查询已过期,你可能根本不想使用缓存数据,而是直接从服务器拉取。为简化此决策过程,你可以改用 queryClient.getQueryState 方法,以获取有关源查询的更多信息,包括一个 state.dataUpdatedAt 时间戳;你可据此判断该查询对你的需求而言是否“足够新鲜”:

TypeScript
1todoQuery = injectQuery(() => ({2  queryKey: ['todo', this.todoId()],3  queryFn: () => fetch(`/todos/${this.todoId()}`),4  initialData: () => {5    // Get the query state6    const state = queryClient.getQueryState(['todos'])7 8    // If the query exists and has data that is no older than 10 seconds...9    if (state && Date.now() - state.dataUpdatedAt <= 10 * 1000) {10      // return the individual todo11      return state.data.find((d) => d.id === this.todoId())12    }13 14    // Otherwise, return undefined and let it fetch from a hard loading state!15  },16}))

本页为 TanStack Query 文档(Angular 版)的非官方中文翻译,原文由上游团队维护,遵循 MIT 许可。 译文如有偏差,以英文原文为准。

译自上游 59d11de