查询失效处理
等待查询变为过期后再重新拉取并不总是可行,尤其是当你明确知道某个查询的数据已因用户操作而过时。为此,QueryClient 提供了 invalidateQueries 方法,让你能智能地标记查询为过期,并可选择同时重新拉取它们!
1// Invalidate every query in the cache2queryClient.invalidateQueries()3// Invalidate every query with a key that starts with `todos`4queryClient.invalidateQueries({ queryKey: ['todos'] })注意:其他使用规范化缓存(normalized cache)的库通常会尝试通过命令式方式或基于 Schema 的推断来用新数据更新本地查询;而 TanStack Query 则为你提供工具,以避免维护规范化缓存所需的大量手动工作,并转而推荐 精准失效处理、后台重新拉取以及最终的原子更新。
当使用 invalidateQueries 使一个查询失效时,会发生两件事:
- 该查询被标记为过期。此过期状态将覆盖
injectQuery或相关函数中配置的任何staleTime设置。 - 如果该查询当前正通过
injectQuery或相关函数进行渲染,则它还会在后台被重新拉取。
使用 invalidateQueries 进行查询匹配
在使用 invalidateQueries 和 removeQueries(以及其他支持部分查询匹配的 API)时,你可以通过前缀匹配多个查询,也可以非常精确地匹配某个特定查询。有关可用过滤器类型的详细信息,请参阅 查询过滤器。
在本示例中,我们可以使用 todos 前缀来使所有查询键以 todos 开头的查询失效:
1import { injectQuery, QueryClient } from '@tanstack/angular-query-experimental'2 3class QueryInvalidationExample {4 readonly queryClient = inject(QueryClient)5 6 invalidateQueries() {7 this.queryClient.invalidateQueries({ queryKey: ['todos'] })8 }9 10 // Both queries below will be invalidated11 todoListQuery = injectQuery(() => ({12 queryKey: ['todos'],13 queryFn: fetchTodoList,14 }))15 todoListQuery = injectQuery(() => ({16 queryKey: ['todos', { page: 1 }],17 queryFn: fetchTodoList,18 }))19}你甚至可以通过向 invalidateQueries 方法传入更具体的查询键,来使带有特定变量的查询失效:
1queryClient.invalidateQueries({2 queryKey: ['todos', { type: 'done' }],3})4 5// The query below will be invalidated6todoListQuery = injectQuery(() => ({7 queryKey: ['todos', { type: 'done' }],8 queryFn: fetchTodoList,9}))10 11// However, the following query below will NOT be invalidated12todoListQuery = injectQuery(() => ({13 queryKey: ['todos'],14 queryFn: fetchTodoList,15}))invalidateQueries API 非常灵活:即使你只想使那些查询键恰好为 todos(即不带任何额外变量或子键)的查询失效,也可以向 invalidateQueries 方法传入 exact: true 选项:
1queryClient.invalidateQueries({2 queryKey: ['todos'],3 exact: true,4})5 6// The query below will be invalidated7todoListQuery = injectQuery(() => ({8 queryKey: ['todos'],9 queryFn: fetchTodoList,10}))11 12// However, the following query below will NOT be invalidated13const todoListQuery = injectQuery(() => ({14 queryKey: ['todos', { type: 'done' }],15 queryFn: fetchTodoList,16}))如果你需要 更精细 的控制,还可以向 invalidateQueries 方法传入一个谓词函数(predicate function)。该函数将接收查询缓存中的每个 Query 实例,并允许你返回 true 或 false,以决定是否使该查询失效:
1queryClient.invalidateQueries({2 predicate: (query) =>3 query.queryKey[0] === 'todos' && query.queryKey[1]?.version >= 10,4})5 6// The query below will be invalidated7todoListQuery = injectQuery(() => ({8 queryKey: ['todos', { version: 20 }],9 queryFn: fetchTodoList,10}))11 12// The query below will be invalidated13todoListQuery = injectQuery(() => ({14 queryKey: ['todos', { version: 10 }],15 queryFn: fetchTodoList,16}))17 18// However, the following query below will NOT be invalidated19todoListQuery = injectQuery(() => ({20 queryKey: ['todos', { version: 5 }],21 queryFn: fetchTodoList,22}))你甚至可以通过向 invalidateQueries 方法传入更具体的查询键,来使带有特定变量的查询失效:
invalidateQueries API 非常灵活:即使你只想使那些查询键恰好为 todos(即不带任何额外变量或子键)的查询失效,也可以向 invalidateQueries 方法传入 exact: true 选项:
如果你需要 更精细 的控制,还可以向 invalidateQueries 方法传入一个谓词函数(predicate function)。该函数将接收查询缓存中的每个 Query 实例,并允许你返回 true 或 false,以决定是否使该查询失效: