主动查询失效 Query Invalidation

等待查询变为过期后才重新获取数据并不总是有效,特别是当你确切知道由于用户的某些操作导致某个查询的数据已经过时时。为此,QueryClient 提供了一个 invalidateQueries 方法,让你能够智能地标记查询为过期,并且还可以选择性地重新获取它们!

// 使缓存中的每个查询都失效
queryClient.invalidateQueries()
// 使查询键以 `todos` 开头的每个查询都失效
queryClient.invalidateQueries({ queryKey: ['todos'] })

注意:其他使用规范化缓存的库会通过命令式操作或模式推断来尝试用新数据更新本地查询,而 TanStack Query 则为你提供了工具,使你能够避免维护规范化缓存所带来的手动工作,并转而推荐针对性的失效、后台重新获取,以及最终的原子更新

当使用 invalidateQueries 使查询失效时,会发生两件事:

  • 该查询被标记为过期(stale)。这种过期状态会覆盖 useQuery 或相关 Hook 中使用的任何 staleTime 配置。

  • 如果该查询当前正通过 useQuery 或相关 Hook 渲染,则它也会在后台重新获取。

使用 invalidateQueries 进行查询匹配

在使用像 invalidateQueriesremoveQueries 这样的 API 时(以及其他支持部分查询匹配的 API),你可以通过前缀匹配多个查询,或者更精确地匹配一个确切的查询。有关可使用的过滤器类型,请参阅 查询过滤器。

在此示例中,我们可以使用 todos 前缀来使查询键以 todos 开头的所有查询失效:

import { useQuery, useQueryClient } from '@tanstack/react-query'

// 从上下文中获取 QueryClient
const queryClient = useQueryClient()

queryClient.invalidateQueries({ queryKey: ['todos'] })

// 以下两个查询都将被失效
const todoListQuery = useQuery({
  queryKey: ['todos'],
  queryFn: fetchTodoList,
})
const todoListQuery = useQuery({
  queryKey: ['todos', { page: 1 }],
  queryFn: fetchTodoList,
})

你甚至可以通过向 invalidateQueries 方法传递一个更具体的查询键来使具有特定变量的查询失效:

queryClient.invalidateQueries({
  queryKey: ['todos', { type: 'done' }],
})

// 以下查询将被失效
const todoListQuery = useQuery({
  queryKey: ['todos', { type: 'done' }],
  queryFn: fetchTodoList,
})

// 但是,以下查询将不会被失效
const todoListQuery = useQuery({
  queryKey: ['todos'],
  queryFn: fetchTodoList,
})

invalidateQueries API 非常灵活,因此即使你只想使查询键为 todos 且没有其他变量或子键的查询失效,你也可以向 invalidateQueries 方法传递一个 exact: true 选项:

queryClient.invalidateQueries({
  queryKey: ['todos'],
  exact: true,
})

// 以下查询将被失效
const todoListQuery = useQuery({
  queryKey: ['todos'],
  queryFn: fetchTodoList,
})

// 但是,以下查询将不会被失效
const todoListQuery = useQuery({
  queryKey: ['todos', { type: 'done' }],
  queryFn: fetchTodoList,
})

如果你需要更精细的控制,可以向 invalidateQueries 方法传递一个谓词函数(predicate function)。该函数将接收查询缓存中的每个 Query 实例,并允许你返回 truefalse 来决定是否使该查询失效:

queryClient.invalidateQueries({
  predicate: (query) =>
    query.queryKey[0] === 'todos' && query.queryKey[1]?.version >= 10,
})

// 以下查询将被失效
const todoListQuery = useQuery({
  queryKey: ['todos', { version: 20 }],
  queryFn: fetchTodoList,
})

// 以下查询将被失效
const todoListQuery = useQuery({
  queryKey: ['todos', { version: 10 }],
  queryFn: fetchTodoList,
})

// 但是,以下查询将不会被失效
const todoListQuery = useQuery({
  queryKey: ['todos', { version: 5 }],
  queryFn: fetchTodoList,
})

最后更新于

这有帮助吗?