框架
版本
指南 & 概念

Query Invalidation (查询失效)

等待查询变为过时状态之后再重新获取数据并不总是有效,特别是当您确切知道由于用户已执行某些操作导致查询数据已过期时。为此,QueryClient 具有 invalidateQueries 方法,可让您智能地将查询标记为过时,并有可能重新获取它们!

tsx
// Invalidate every query in the cache
queryClient.invalidateQueries()
// Invalidate every query with a key that starts with `todos`
queryClient.invalidateQueries({ queryKey: ['todos'] })
// Invalidate every query in the cache
queryClient.invalidateQueries()
// Invalidate every query with a key that starts with `todos`
queryClient.invalidateQueries({ queryKey: ['todos'] })

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

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

  • 它被标记为过时。此过时状态会覆盖在 useQuery 或相关 Hook 中使用的任何 staleTime 配置
  • 如果当前正在通过 useQuery 或相关 Hook 渲染查询,它也将在后台重新获取

使用 invalidateQueries 进行 Query Matching (查询匹配)

当使用诸如 invalidateQueriesremoveQueries (以及其他支持部分查询匹配的方法) 之类的 API 时,您可以通过它们的前缀匹配多个查询,或者非常具体地匹配精确的查询。有关您可以使用的过滤器类型的信息,请参阅 Query Filters (查询过滤器)

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

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

// Get QueryClient from the context
const queryClient = useQueryClient()

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

// Both queries below will be invalidated
const todoListQuery = useQuery({
  queryKey: ['todos'],
  queryFn: fetchTodoList,
})
const todoListQuery = useQuery({
  queryKey: ['todos', { page: 1 }],
  queryFn: fetchTodoList,
})
import { useQuery, useQueryClient } from '@tanstack/react-query'

// Get QueryClient from the context
const queryClient = useQueryClient()

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

// Both queries below will be invalidated
const todoListQuery = useQuery({
  queryKey: ['todos'],
  queryFn: fetchTodoList,
})
const todoListQuery = useQuery({
  queryKey: ['todos', { page: 1 }],
  queryFn: fetchTodoList,
})

您甚至可以通过将更具体的查询键传递给 invalidateQueries 方法来使具有特定变量的查询失效

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

// The query below will be invalidated
const todoListQuery = useQuery({
  queryKey: ['todos', { type: 'done' }],
  queryFn: fetchTodoList,
})

// However, the following query below will NOT be invalidated
const todoListQuery = useQuery({
  queryKey: ['todos'],
  queryFn: fetchTodoList,
})
queryClient.invalidateQueries({
  queryKey: ['todos', { type: 'done' }],
})

// The query below will be invalidated
const todoListQuery = useQuery({
  queryKey: ['todos', { type: 'done' }],
  queryFn: fetchTodoList,
})

// However, the following query below will NOT be invalidated
const todoListQuery = useQuery({
  queryKey: ['todos'],
  queryFn: fetchTodoList,
})

invalidateQueries API 非常灵活,因此即使您只想使没有更多变量或子键的 todos 查询失效,也可以将 exact: true 选项传递给 invalidateQueries 方法

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

// The query below will be invalidated
const todoListQuery = useQuery({
  queryKey: ['todos'],
  queryFn: fetchTodoList,
})

// However, the following query below will NOT be invalidated
const todoListQuery = useQuery({
  queryKey: ['todos', { type: 'done' }],
  queryFn: fetchTodoList,
})
queryClient.invalidateQueries({
  queryKey: ['todos'],
  exact: true,
})

// The query below will be invalidated
const todoListQuery = useQuery({
  queryKey: ['todos'],
  queryFn: fetchTodoList,
})

// However, the following query below will NOT be invalidated
const todoListQuery = useQuery({
  queryKey: ['todos', { type: 'done' }],
  queryFn: fetchTodoList,
})

如果您发现自己想要更精细的粒度,则可以将谓词函数传递给 invalidateQueries 方法。此函数将接收查询缓存中的每个 Query 实例,并允许您返回 truefalse,以指示您是否要使该查询失效

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

// The query below will be invalidated
const todoListQuery = useQuery({
  queryKey: ['todos', { version: 20 }],
  queryFn: fetchTodoList,
})

// The query below will be invalidated
const todoListQuery = useQuery({
  queryKey: ['todos', { version: 10 }],
  queryFn: fetchTodoList,
})

// However, the following query below will NOT be invalidated
const todoListQuery = useQuery({
  queryKey: ['todos', { version: 5 }],
  queryFn: fetchTodoList,
})
queryClient.invalidateQueries({
  predicate: (query) =>
    query.queryKey[0] === 'todos' && query.queryKey[1]?.version >= 10,
})

// The query below will be invalidated
const todoListQuery = useQuery({
  queryKey: ['todos', { version: 20 }],
  queryFn: fetchTodoList,
})

// The query below will be invalidated
const todoListQuery = useQuery({
  queryKey: ['todos', { version: 10 }],
  queryFn: fetchTodoList,
})

// However, the following query below will NOT be invalidated
const todoListQuery = useQuery({
  queryKey: ['todos', { version: 5 }],
  queryFn: fetchTodoList,
})