主动查询失效 Query Invalidation

等待查询变为陈旧(stale)后再重新获取数据的方式并不总是有效,尤其是在用户执行某些操作后,你已经明确知道查询数据已过时的情况下。为此,QueryClient 提供了 invalidateQueries 方法,它可以智能地标记查询为陈旧状态,并且在适当情况下重新获取数据。

失效查询示例

// 使缓存中的所有查询失效
queryClient.invalidateQueries();

// 使所有以 'todos' 开头的查询失效
queryClient.invalidateQueries({ queryKey: ["todos"] });

👀 注意: 与其他使用标准化缓存的库不同,那些库可能会尝试使用命令式方式或基于模式推断来更新本地查询数据,而 TanStack Query 提供了更灵活的工具,使你能够避免手动维护标准化缓存的负担,而是采用目标明确的失效策略、后台重新获取数据以及最终的原子性更新。

当某个查询通过 invalidateQueries 失效时,会发生以下两件事:

  1. 该查询会被标记为陈旧(stale),并且这个陈旧状态会覆盖 useQuery 或相关 Hook 中的 staleTime 配置。

  2. 如果该查询当前正在 useQuery 或相关 Hook 中渲染,它还会在后台自动重新获取数据。

invalidateQueries 的查询匹配机制

当使用 invalidateQueriesremoveQueries 以及其他支持部分匹配的 API 时,你可以按照查询键前缀进行匹配,或者精确匹配一个查询。

例如,我们可以使用 todos 作为前缀,使所有 queryKeytodos 开头的查询失效:

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

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

// 使所有 `queryKey` 以 `todos` 开头的查询失效
queryClient.invalidateQueries({ queryKey: ["todos"] });

// 下面的两个查询都会被失效处理
const todoListQuery = useQuery({
  queryKey: ["todos"],
  queryFn: fetchTodoList,
});

const todoListQuery = useQuery({
  queryKey: ["todos", { page: 1 }],
  queryFn: fetchTodoList,
});

你甚至可以通过传递更具体的 queryKey 来使特定查询失效:

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

// 下面的查询会被失效
const todoListQuery = useQuery({
  queryKey: ["todos", { type: "done" }],
  queryFn: fetchTodoList,
});

// 但这个查询不会受到影响
const todoListQuery = useQuery({
  queryKey: ["todos"],
  queryFn: fetchTodoList,
});

invalidateQueries 的精确匹配

如果你希望仅失效 todos 查询,而不影响带有额外参数的查询,可以使用 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 选项,它允许你传入一个自定义匹配函数,该函数会接收每个缓存中的 Query 实例,并返回 true(使查询失效)或 false(保留查询)。

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,
});

🚚 总结:

  • invalidateQueries 允许你手动使查询失效,并在需要时触发后台重新获取数据。

  • 你可以使用 queryKey 进行部分或精确匹配来控制哪些查询应该被失效。

  • 你可以传入 predicate 方法,自定义更细粒度的查询失效逻辑。

最后更新于

这有帮助吗?