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

初始查询数据

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

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

使用 initialData 预填充查询

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

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

TypeScript
1const result = useQuery({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 todos after mount2  const result = useQuery({3    queryKey: ['todos'],4    queryFn: () => fetch('/todos'),5    initialData: initialTodos,6  })
  • 若你为查询观察者同时配置了 initialData 和 staleTime(例如 1000 毫秒),则该数据将在相同时间内被视为新鲜数据,就如同刚从你的查询函数中拉取一样。

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

TypeScript
1  // Show initialTodos immediately, but won't refetch until another interaction event is encountered after 1000 ms2  const result = useQuery({3    queryKey: ['todos'],4    queryFn: () => fetch('/todos'),5    initialData: initialTodos,6    staleTime: 60 * 1000, // 1 minute7    // This could be 10 seconds ago or 10 minutes ago8    initialDataUpdatedAt: initialTodosUpdatedTimestamp, // eg. 16084124200529  })

此选项使 staleTime 可以回归其原始用途,即判断数据的新鲜程度;同时,若 initialData 的更新时间早于 staleTime 所定义的时限,该数据仍会在挂载时被重新拉取。在上述示例中,我们的数据需在一分钟内保持新鲜,且我们可通过提示查询初始数据的最后更新时间,让查询自行决定是否需要再次重新拉取。

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

初始数据函数

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

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

来自缓存的初始数据

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

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

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

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

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

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

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

TypeScript
1const result = useQuery({2  queryKey: ['todo', todoId],3  queryFn: () => fetch(`/todos/${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 === todoId)12    }13 14    // Otherwise, return undefined and let it fetch from a hard loading state!15  },16})

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

译自上游 59d11de