在您需要查询的初始数据之前,有多种方法可以将其提供给缓存
有时,您可能已在应用中备有查询的初始数据,并可以直接将其提供给查询。在这种情况下,您可以使用 config.initialData 选项来设置查询的初始数据,从而跳过初始加载状态!
重要提示:initialData 会持久化到缓存中,因此不建议为此选项提供占位符、部分或不完整的数据,而应使用 placeholderData。
result = injectQuery(() => ({
queryKey: ['todos'],
queryFn: () => fetch('/todos'),
initialData: initialTodos,
}))
result = injectQuery(() => ({
queryKey: ['todos'],
queryFn: () => fetch('/todos'),
initialData: initialTodos,
}))
默认情况下,initialData 会被视为完全新鲜的数据,就像刚刚获取一样。这也意味着它将影响 staleTime 选项的解释方式。
// Will show initialTodos immediately, but also immediately refetch todos
// when an instance of the component or service is created
result = injectQuery(() => ({
queryKey: ['todos'],
queryFn: () => fetch('/todos'),
initialData: initialTodos,
}))
// Will show initialTodos immediately, but also immediately refetch todos
// when an instance of the component or service is created
result = injectQuery(() => ({
queryKey: ['todos'],
queryFn: () => fetch('/todos'),
initialData: initialTodos,
}))
// Show initialTodos immediately, but won't refetch until
// another interaction event is encountered after 1000 ms
result = injectQuery(() => ({
queryKey: ['todos'],
queryFn: () => fetch('/todos'),
initialData: initialTodos,
staleTime: 1000,
}))
// Show initialTodos immediately, but won't refetch until
// another interaction event is encountered after 1000 ms
result = injectQuery(() => ({
queryKey: ['todos'],
queryFn: () => fetch('/todos'),
initialData: initialTodos,
staleTime: 1000,
}))
// Show initialTodos immediately, but won't refetch until
// another interaction event is encountered after 1000 ms
result = injectQuery(() => ({
queryKey: ['todos'],
queryFn: () => fetch('/todos'),
initialData: initialTodos,
staleTime: 60 * 1000, // 1 minute
// This could be 10 seconds ago or 10 minutes ago
initialDataUpdatedAt: initialTodosUpdatedTimestamp, // eg. 1608412420052
}))
// Show initialTodos immediately, but won't refetch until
// another interaction event is encountered after 1000 ms
result = injectQuery(() => ({
queryKey: ['todos'],
queryFn: () => fetch('/todos'),
initialData: initialTodos,
staleTime: 60 * 1000, // 1 minute
// This could be 10 seconds ago or 10 minutes ago
initialDataUpdatedAt: initialTodosUpdatedTimestamp, // eg. 1608412420052
}))
此选项允许 staleTime 用于其原始目的,即确定数据的“新鲜度”,同时还允许在初始化时重新获取数据,如果 initialData 比 staleTime 旧的话。在上面的示例中,我们的数据需要在一分钟内保持新鲜,并且我们可以提示查询 initialData 最后更新的时间,以便查询可以自行决定是否需要再次重新获取数据。
如果您更愿意将数据视为**预取数据**,我们建议您使用 prefetchQuery 或 fetchQuery API 来提前填充缓存,从而允许您独立于 initialData 来配置 staleTime。
如果访问查询初始数据的过程非常耗时,或者您不想在每次服务或组件实例中都执行此操作,您可以将一个函数作为 initialData 的值传递。此函数将在查询初始化时仅执行一次,从而为您节省宝贵的内存和/或 CPU。
result = injectQuery(() => ({
queryKey: ['todos'],
queryFn: () => fetch('/todos'),
initialData: () => getExpensiveTodos(),
}))
result = injectQuery(() => ({
queryKey: ['todos'],
queryFn: () => fetch('/todos'),
initialData: () => getExpensiveTodos(),
}))
在某些情况下,您可能可以从另一个查询的缓存结果中获取查询的初始数据。一个很好的例子是搜索一个 todos 列表查询的缓存数据以查找单个 todo 项目,然后将其用作单个 todo 查询的初始数据。
result = injectQuery(() => ({
queryKey: ['todo', this.todoId()],
queryFn: () => fetch('/todos'),
initialData: () => {
// Use a todo from the 'todos' query as the initial data for this todo query
return this.queryClient
.getQueryData(['todos'])
?.find((d) => d.id === this.todoId())
},
}))
result = injectQuery(() => ({
queryKey: ['todo', this.todoId()],
queryFn: () => fetch('/todos'),
initialData: () => {
// Use a todo from the 'todos' query as the initial data for this todo query
return this.queryClient
.getQueryData(['todos'])
?.find((d) => d.id === this.todoId())
},
}))
从缓存中获取初始数据意味着您用来查找初始数据的源查询可能已过时。与其使用人工设置的 staleTime 来防止查询立即重新获取,不如建议您将源查询的 dataUpdatedAt 传递给 initialDataUpdatedAt。这为查询实例提供了确定查询是否以及何时需要重新获取的所有必要信息,无论是否提供了初始数据。
result = injectQuery(() => ({
queryKey: ['todos', this.todoId()],
queryFn: () => fetch(`/todos/${this.todoId()}`),
initialData: () =>
queryClient.getQueryData(['todos'])?.find((d) => d.id === this.todoId()),
initialDataUpdatedAt: () =>
queryClient.getQueryState(['todos'])?.dataUpdatedAt,
}))
result = injectQuery(() => ({
queryKey: ['todos', this.todoId()],
queryFn: () => fetch(`/todos/${this.todoId()}`),
initialData: () =>
queryClient.getQueryData(['todos'])?.find((d) => d.id === this.todoId()),
initialDataUpdatedAt: () =>
queryClient.getQueryState(['todos'])?.dataUpdatedAt,
}))
如果源查询已过时,您可能根本不想使用缓存数据,而只想从服务器获取。为了使此决策更容易,您可以使用 queryClient.getQueryState 方法来获取有关源查询的更多信息,包括一个 state.dataUpdatedAt 时间戳,您可以使用它来决定查询是否“新鲜”到满足您的需求。
result = injectQuery(() => ({
queryKey: ['todo', this.todoId()],
queryFn: () => fetch(`/todos/${this.todoId()}`),
initialData: () => {
// Get the query state
const state = queryClient.getQueryState(['todos'])
// If the query exists and has data that is no older than 10 seconds...
if (state && Date.now() - state.dataUpdatedAt <= 10 * 1000) {
// return the individual todo
return state.data.find((d) => d.id === this.todoId())
}
// Otherwise, return undefined and let it fetch from a hard loading state!
},
}))
result = injectQuery(() => ({
queryKey: ['todo', this.todoId()],
queryFn: () => fetch(`/todos/${this.todoId()}`),
initialData: () => {
// Get the query state
const state = queryClient.getQueryState(['todos'])
// If the query exists and has data that is no older than 10 seconds...
if (state && Date.now() - state.dataUpdatedAt <= 10 * 1000) {
// return the individual todo
return state.data.find((d) => d.id === this.todoId())
}
// Otherwise, return undefined and let it fetch from a hard loading state!
},
}))