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

初始化的查询数据 Initial Query Data

在需要查询之前,有很多方法可以向缓存提供初始数据:

使用initialData预先填充查询

有时候,你可能已经在应用中其他地方获得了查询的初始数据,并且可以直接将其提供给你的查询。 在这种情况下,则可以使用config.initialData选项设置查询的初始数据,并跳过初始加载状态!

重要说明:initialData保留在缓存中,因此不建议为此选项提供占位符,部分或不完整的数据,如有必要,应使用placeholderData

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

staleTime 和 initialDataUpdatedAt

默认情况下,initialData被视为完全新鲜的数据,就像它刚刚被获取一样。这也意味着它将影响staleTime对它的解释。

  • 如果为查询观察者(query observer)配置了initialData且没有staleTime(默认的staleTime: 0),则该查询在挂载时将立即重新获取:

    TypeScript
    1// 将立即显示 initialTodos,但在挂载后也将立即重新获取todos2const result = useQuery({3  queryKey: ["todos"],4  queryFn: () => fetch("/todos"),5  initialData: initialTodos,6});
  • 如果为查询观察者(query observer)配置了initialData且staleTime为1000ms,则在相同的时间量内数据将被视为最新数据,就好像它是刚从查询中获取的一样

    TypeScript
    1// 立即显示 initialTodos,但是直到 1000 ms 之后遇到另一个交互事件时才重新获取数据2const result = useQuery({3  queryKey: ["todos"],4  queryFn: () => fetch("/todos"),5  initialData: initialTodos,6  staleTime: 1000,7});
  • 那么,如果你的initialData并不完全新鲜怎么办?这就引出了最后一个--实际上也是最为准确的--名为initialDataUpdatedAt的配置项。该选项允许你传递一个Number类型的 JS 时间戳(以毫秒为单位,如Date.now()),以确定initialData上次更新的时间。请注意,如果是 unix 时间戳,则需要将其乘以 1000,以将其转换为 JS 时间戳

    TypeScript
    1// 立即显示 initialTodos,但是直到 1000 ms 之后遇到另一个交互事件时才重新获取数据2const result = useQuery({3  queryKey: ["todos"],4  queryFn: () => fetch("/todos"),5  initialData: initialTodos,6  staleTime: 60 * 1000,7  initialData: initialTodos,8  staleTime: 60 * 1000, // 1 minute9  // 这可能是10秒前或10分钟前10  initialDataUpdatedAt: initialTodosUpdatedTimestamp, // eg. 160841242005211});

    此选项允许将 staleTime 用于其"原始"用途,以确定数据需要有多新鲜,同时还允许:如果 initialData 早于 staleTime,则在挂载时重新获取数据。在上面的示例中,我们的数据需要在 1 分钟内刷新,我们可以在initialData最后一次更新时提示查询,以便查询自己决定是否需要重新获取数据。

如果你希望将数据视为预取数据,建议你使用prefetchQuery或fetchQuery API 来预先填充缓存,从而独立于initialData配置staleTime。

来自函数的初始数据

如果访问查询的初始数据的过程很繁琐,或者只是不想在每个渲染上执行某些操作,则可以传递一个函数作为initialData值。这个函数只在初始化查询时执行一次,从而节省宝贵的 RAM 和或 CPU。

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

来自缓存的初始数据

在某些情况下,你可能希望能够从另一个查询的缓存结果中为查询提供初始数据。一个很好的例子是,从一个 todos list 查询中搜索一个单独的 todo 项,然后使用该项对应的已被缓存的数据,来作为单独的 todo 查询的初始数据:

JavaScript
1const result = useQuery({2  queryKey: ["todo", todoId],3  queryFn: () => fetch("/todos"),4  initialData: () => {5    // 将 `todos` 查询中的某个 todo 用作此 todos 查询的初始数据6    return queryClient.getQueryData(["todos"])?.find((d) => d.id === todoId);7  },8});

来自配置InitialDataUpdatedAt的缓存的初始数据

从缓存中获取初始数据意味着,哪怕使用了initialData,用来查询初始数据的源查询还是有可能很旧。建议不要手动设置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    // 获取查询状态6    const state = queryClient.getQueryState(["todos"]);7 8    // 如果查询存在并且数据"老得"不超过10秒...9    if (state && Date.now() - state.dataUpdatedAt <= 10 * 1000) {10      // 返回单个todo11      return state.data.find((d) => d.id === todoId);12    }13 14    // 否则,返回undefined并让它从硬加载状态获取!15  },16});

延伸阅读

如果对于Initial Data和Placeholder Data有困惑的话,请参考此社区内容(英文)

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

本页译文取自社区中文版 react-query-web-i18n(MIT),非本站翻译,已停止更新,内容可能与当前 API 有出入。

译自上游 (未记录版本)