Angular Query 中从 Mutation 触发查询失效:injectMutation 与 invalidateQueries 实战指南

Angular Query 中从 Mutation 触发查询失效:injectMutation 与 invalidateQueries 实战指南 Angular Query 中从 Mutation 触发查询失效injectMutation 与 invalidateQueries 实战指南【免费下载链接】query Powerful asynchronous state management, server-state utilities and data fetching for the web. TS/JS, React Query, Solid Query, Svelte Query and Vue Query.项目地址: https://gitcode.com/GitHub_Trending/qu/query在 TanStack Query 的 Angular 集成tanstack/angular-query-experimental中让查询失效只是数据同步的一半工作另一半是弄清楚何时失效。当一次 mutation比如新增一条 Todo成功后应用里几乎必然存在与之相关的查询Todo 列表、提醒列表等需要被失效并重新拉取以反映服务端的新状态。本文围绕 Invalidations from Mutations 指南 展开讲解如何在injectMutation的回调中接线QueryClient.invalidateQueries并结合 query-core 源码 剖析失效-重取机制的底层行为帮助你在 Angular 应用中建立可靠的mutation 成功 → 关联查询刷新数据流。场景一次 postTodo mutation 需要刷新多个查询假设应用里有一个提交新 Todo 的 mutation。最基础的写法只是声明mutationFnmutation injectMutation(() ({ mutationFn: postTodo, }))当postTodo成功后我们大概率希望所有todos查询被失效、重新取数从而展示新加入的 Todo 项同理如果 Todo 关联了提醒remindersreminders查询也需要刷新。在 onSuccess 中接线 invalidateQueriesAngular 版指南给出的完整用法是通过injectMutation的onSuccess选项配合通过 DI 注入的QueryClient实例的invalidateQueries方法完成失效import { injectMutation, QueryClient, } from tanstack/angular-query-experimental export class TodosComponent { queryClient inject(QueryClient) // When this mutation succeeds, invalidate any queries with the todos or reminders query key mutation injectMutation(() ({ mutationFn: addTodo, onSuccess: () { this.queryClient.invalidateQueries({ queryKey: [todos] }) this.queryClient.invalidateQueries({ queryKey: [reminders] }) }, })) }要点说明queryClient的来源Angular 侧不像 React 有useQueryClient()Hook而是直接inject(QueryClient)QueryClient需在根模块/应用配置中注册为 DI provider。这也与 queries 指南 和 query-invalidation 指南 中injectQuery的用法保持一致。queryKey前缀匹配invalidateQueries({ queryKey: [todos] })会匹配所有以[todos, ...]开头的查询例如[todos]和[todos, { page: 1 }]都会命中。匹配规则含exact与predicate用法在 query-invalidation 指南 中有完整说明。失效不止影响正在展示的查询invalidateQueries的第二个参数中refetchType默认为active即默认只重取活跃有观察者订阅的查询被标记失效的查询即使处于 inactive 状态下次重新挂载时也会立即重取。并行失效多个 keyReact 版文档建议用Promise.all([...])并发调用多个invalidateQueriesAngular 版示例中直接顺序发起两个调用效果相同。若需要保证失效与后续重取完成后再继续例如等待 UI 更新完毕再跳转可以像 React 文档那样把onSuccess声明为async并await这些 Promise。回调的可选性与 React 的useMutation一样失效逻辑不只能放在onSuccess任何可用的 mutation 回调onMutate、onError、onSettled等都可以承担接线工作完整的回调体系参见 mutations 指南。源码印证onSuccess 何时执行、invalidateQueries 内部做了什么从 Mutation 核心实现 可以看到mutationFn成功返回后执行顺序是先awaitMutationCache 级别的onSuccessqueryClient.setMutationDefaults注册的默认回调再await本 mutation 自己options.onSuccess——也就是你接线invalidateQueries的地方最后才是各级onSettled。由于onSuccess是await的如果你在其中返回/await 一个 Promise例如await this.queryClient.invalidateQueries(...)那么 mutation 的状态要等onSuccess完成才会进入successisPending会保持为 true 直到失效触发的重取完成。这就是让数据先更新、mutation 才算真正完成的语义来源。再看invalidateQueries本体的实现queryClient.tsinvalidateQueries(filters?, options {}): Promisevoid { return notifyManager.batch(() { this.#queryCache.findAll(filters).forEach((query) { query.invalidate() }) if (filters?.refetchType none) { return Promise.resolve() } return this.refetchQueries( { ...filters, type: filters?.refetchType ?? filters?.type ?? active, }, options, ) }) }这段源码揭示了三个事实第一步是标记失效queryCache.findAll(filters)按过滤器queryKey前缀、predicate、type等选出所有匹配 Query逐一调用query.invalidate()将isInvalidated置为 true第二步是按类型重取随后委托给refetchQueries默认type为active如果你传入refetchType: all/none可以改变重取范围none只标记不重取整个操作包裹在notifyManager.batch中失效与批量重取的状态更新会被合并通知避免每次setQueries都触发一次渲染——对 Angular 的变更检测来说是重要的性能保障。另外refetchQueries默认带cancelRefetch: truequeryClient.ts即新的重取请求会取消同 key 正在进行的旧请求防止竞态导致的旧数据覆盖新数据。Angular 侧的注入与响应式细节injectMutation的实现在 inject-mutation.ts有两个与失效接线直接相关的细节QueryClient 从 Injector 获取inject-mutation.ts#L60-L63const queryClient injector.get(QueryClient)所以QueryClient必须已经注册到注入器中否则injectMutation会在注入阶段失败。onSuccess 在 Angular 变更检测内执行mutation 的订阅回调先ngZone.runOutsideAngular处理再ngZone.run(...)把状态变更写回信号inject-mutation.ts#L136-L163。因此在onSuccess中触发的invalidateQueries最终引起的数据更新会正确地落入 Angular 的变更检测周期模板中的if (mutation.isSuccess())等状态切换能及时刷新。isPending 与 Pending Tasks 的联动当state.isPending为真时Angular 包会通过pendingTasks.add()挂起应用级别的 pending taskinject-mutation.ts#L142-L150。在 SSR/应用启动场景下mutation 未 settled 之前应用不会过早完成由于onSuccess是 awaited 的你在其中等待的失效与重取也会自然延长这个窗口。失效粒度的进阶手段invalidateQueries的过滤器非常灵活从 query-invalidation 指南 可以继承三档粒度到 mutation 回调中使用// 1. 前缀匹配默认todos 及其所有子 key this.queryClient.invalidateQueries({ queryKey: [todos] }) // 2. exact 精确匹配只有 key 恰好为 [todos] 的查询 this.queryClient.invalidateQueries({ queryKey: [todos], exact: true }) // 3. predicate 自定义判断按 key 内变量精细筛选 this.queryClient.invalidateQueries({ predicate: (query) query.queryKey[0] todos query.queryKey[1]?.version 10, })在 mutation 场景里predicate尤其有用例如只刷新与本次 mutation 修改的那条记录相关的分页查询避免把无关列表全部打回 loading 态。参考实现仓库中的 Angular 示例工程仓库自带多个 Angular 示例可以对照学习optimistic-updates 示例展示injectQueryinjectMutation的组合mutation 成功/失败时通过回调刷新与回滚任务列表——其 mutation 选项onMutate乐观写入、onSuccess重取真实数据、onError回滚正由 services/tasks.service.ts 中的addTask()返回的 options 对象定义是把失效/更新逻辑集中到服务层的实践参考basic 示例最小化的injectQuery/injectMutation入门工程auto-refetching 示例展示失效后自动重取在真实请求场景中的表现。这些示例的injectMutation(() service.options())写法与本文的回调接线方式完全兼容——把onSuccess里的queryClient.invalidateQueries移到 service 返回的 options 中即可让同一份 mutation 定义在多个组件间复用失效策略也随之统一。小结在 Angular Query 中mutation 成功后刷新数据的标准模式是inject(QueryClient)injectMutation的onSuccess或其他回调中调用invalidateQueriesinvalidateQueries的语义是按过滤器标记失效 按refetchType默认active批量重取全程包在notifyManager.batch中底层实现在 packages/query-core/src/queryClient.tsonSuccess是 awaited 的在其中await失效 Promise 可以让 mutation 的isPending覆盖到重取完成为止保证 UI 状态与数据一致用queryKey前缀、exact、predicate三档工具控制失效粒度避免无差别刷新。【免费下载链接】query Powerful asynchronous state management, server-state utilities and data fetching for the web. TS/JS, React Query, Solid Query, Svelte Query and Vue Query.项目地址: https://gitcode.com/GitHub_Trending/qu/query创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考