拓冰建站拓冰建站
首页 / 资讯中心 / 正文

Vue Query 的 useMutationState:在 MutationCache 之上订阅与转换全局变更状态

Vue Query 的 useMutationState在 MutationCache 之上订阅与转换全局变更状态【免费下载链接】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/queryuseMutationState是 TanStack Vue Query 提供的一个组合式 API用于访问MutationCache中全部或经筛选后的mutation 状态。它适用于跨组件监控异步变更的中间状态例如同时展示多个提交中的按钮、收集所有进行中 mutation 的 variables、或在某个 mutation 完成后统一刷新 UI。读完本文你将掌握useMutationState的完整选项、MutationFilters的匹配规则、select的状态转换写法以及其底层的响应式订阅原理并能在 Vue 3 / Vue 2.7vue-demi项目中直接落地使用。本文以仓库中的官方参考文档 docs/framework/vue/reference/useMutationState.md 为主体结合vue-query与query-core的源码与测试用例展开。相关完整 API 还可对照参考 useMutation、useIsMutating 与 mutationOptions。一、useMutationState 是什么订阅 MutationCache 的全局观测器与useMutation的单点操控不同useMutationState更像一个全局观测器它读的是QueryClient内部MutationCache中当前存活的所有 mutation而不是某一个 mutation 实例。看它的源码定义 packages/vue-query/src/useMutationState.tsexport function useMutationStateTResult MutationState, ...( options: | MutationStateOptionsTResult, TMutation | (() MutationStateOptionsTResult, TMutation) {}, queryClient?: QueryClient, ): ReadonlyRefArrayTResult { const resolvedOptions computed(() { const newOptions typeof options function ? options() : options return { filters: cloneDeepUnref(newOptions.filters), select: newOptions.select, } }) const mutationCache (queryClient || useQueryClient()).getMutationCache() const state shallowRef(getResult(mutationCache, resolvedOptions.value)) const unsubscribe mutationCache.subscribe(() { state.value getResult(mutationCache, resolvedOptions.value) }) watch(resolvedOptions, () { state.value getResult(mutationCache, resolvedOptions.value) }) onScopeDispose(() { unsubscribe() }) return shallowReadonly(state) }关键实现细节均来自该文件数据源是MutationCache通过(queryClient || useQueryClient()).getMutationCache()取得全局缓存。若不传queryClient则自动使用最近上下文provide/inject或QueryClientProvider中的实例。getResult的调用链mutationCache.findAll(filters)先按MutationFilters过滤再对每个匹配的 mutation 执行select(mutation)未提供select时直接返回mutation.state见 packages/vue-query/src/useMutationState.ts。响应式更新返回的是shallowReadonly(shallowRef(...))。当mutationCache触发added/updated/removed等订阅事件时重新计算结果同时watch(resolvedOptions, ...)让filters/select的变化也触发重算。生命周期通过onScopeDispose取消订阅因此它必须运行在setup()或 effect scope 内否则可能造成内存泄漏useIsMutating的开发警告也与此相关见同一文件的useIsMutating实现。从源码结构看useIsMutating实际上是useMutationState的薄封装它把filters强制合并status: pending后交给useMutationState再取length见 packages/vue-query/src/useMutationState.ts。二、Options 完整说明官方文档 docs/framework/vue/reference/useMutationState.md 给出的选项如下下面补充类型与默认行为选项类型说明options.filtersMutationFilters可选用于缩小要匹配的 mutation 范围详见第三节。注意这里支持MaybeRefDeep即可以直接传ref/ 响应式对象也可以传 getter 函数。options.select(mutation: Mutation) TResult可选对每个匹配到的 mutation 进行状态转换返回的值组成结果数组。省略时返回mutation.state。queryClientQueryClient可选传入自定义 QueryClient不传则使用最近上下文中的实例。对应源码中的MutationStateOptions类型packages/vue-query/src/useMutationState.tsexport type MutationStateOptionsTResult MutationState, ... { filters?: MutationFilters select?: (mutation: TMutation) TResult }此外options本身既可以传对象也可以传函数() MutationStateOptions。从源码resolvedOptions的computed可以看出传入函数时每次响应式依赖变化都会重新求值配合cloneDeepUnref自动对filters内的ref解包。这一点在测试 packages/vue-query/src/tests/useMutationState.test.ts 中有直接验证修改keyRef.value后无需重新调用组合式函数结果立即响应式更新。返回值ReadonlyRefArrayTResult—— 一个只读的 ref其.value是select对每个匹配 mutation 处理后结果的数组。在模板中可直接访问mutationStateVue 会自动解包在script setup中则用mutationState.value。三、MutationFilters如何精确圈定目标 mutationfilters的类型即MutationFilters完整字段来自 packages/query-core/src/utils.ts 与官方 Filters 指南 docs/framework/react/guides/filters.mdVue 侧通过ref字段复用同一份内容mutationKey?: MutationKey按 mutation key 匹配。不传exact时是前缀包含式匹配partial match即传入[posts]会匹配[posts, 1]等所有以该 key 开头的 mutation。exact?: booleantrue时要求 key完全相等才匹配。status?: MutationStatus按状态过滤。MutationStatus定义为idle | pending | success | error见 packages/query-core/src/types.ts。predicate?: (mutation: Mutation) boolean最终过滤器对每个候选 mutation 求值可用它实现按variables、data等任意条件的细粒度筛选。对应matchMutation的核心匹配逻辑packages/query-core/src/utils.tsexport function matchMutation(filters: MutationFilters, mutation: Mutationany, any): boolean { const { exact, status, predicate, mutationKey } filters if (mutationKey) { if (!mutation.options.mutationKey) return false if (exact) { if (hashKey(mutation.options.mutationKey) ! hashKey(mutationKey)) return false } else if (!partialMatchKey(mutation.options.mutationKey, mutationKey)) { return false } } // ... 后续再按 status、predicate 过滤 }注意区分MutationCache.find单查默认exact: true而findAll供useMutationState使用默认exact: false即默认按 key 前缀模糊匹配。如果只想命中某个完全相同的 key记得显式加exact: true。四、三个官方示例从取 variables 到取最新一次结果示例 1获取所有进行中 mutation 的 variablesimport { useMutationState } from tanstack/vue-query const variables useMutationState({ filters: { status: pending }, select: (mutation) mutation.state.variables, })这里variables.value是当前所有pendingmutation 的variables数组非常适合在列表页展示N 个请求提交中。示例 2通过 mutationKey 获取特定 mutation 的 dataimport { useMutation, useMutationState } from tanstack/vue-query const mutationKey [posts] // 需要与该 mutation 的 key 保持一致 const mutation useMutation({ mutationKey, mutationFn: (newPost) { return axios.post(/posts, newPost) }, }) const data useMutationState({ filters: { mutationKey }, select: (mutation) mutation.state.data, })data.value中是所有 key 以[posts]开头的 mutation 的成功数据。若一个 mutation 执行了多次数组会包含多次记录见示例 3 的说明。示例 3访问同一 mutationKey 下最新一次调用的数据mutate每调用一次就会向 mutation cache 中新增一条记录并在gcTime毫秒后才被清理默认 gcTime 见QueryClient默认配置。因此useMutationState返回的数组是按调用顺序追加的最新一次永远是最后一个元素import { useMutation, useMutationState } from tanstack/vue-query const mutationKey [posts] const mutation useMutation({ mutationKey, mutationFn: (newPost) { return axios.post(/posts, newPost) }, }) const data useMutationState({ filters: { mutationKey }, select: (mutation) mutation.state.data, }) // 最新一次 mutation 的数据 const latest data.value[data.value.length - 1]结合 packages/query-core/src/mutationCache.ts 可知MutationCache内部用Set保存全部 mutationuseMutation的每次调用都会经build()产生一个新实例并add()进缓存随后触发added通知——这正是useMutationState数组会越变越长、需要取[length - 1]的根本原因。缓存清理则由gcTime默认 5 分钟可在QueryClient或QueryCache级别覆盖控制。五、进阶用法1. 用 getter 让 filters 响应式当筛选条件本身依赖其它响应式状态时直接传函数即可无需手动 watchimport { ref } from vue import { useMutationState } from tanstack/vue-query const filterStatus refidle | pending | success | error(pending) const states useMutationState(() ({ filters: { status: filterStatus.value }, select: (mutation) mutation.state, }))2. 用 predicate 做任意条件筛选例如只看某个 userId 的 mutationconst states useMutationState({ filters: { predicate: (mutation) mutation.state.variables?.userId currentUserId, }, select: (mutation) mutation.state, })3. 结合 select 提取结构化数据select可以返回任意结构常见做法是返回一个可观察对象配合 Vue 模板或computed聚合统计const summary useMutationState({ filters: { status: pending }, select: (mutation) ({ id: mutation.options.mutationKey, variables: mutation.state.variables, error: mutation.state.error, }), })4. 自定义 QueryClient在测试或多客户端场景下可显式传入import { useQueryClient, useMutationState } from tanstack/vue-query const client useQueryClient() const states useMutationState({ filters: { status: pending } }, client)六、测试佐证行为即契约仓库测试 packages/vue-query/src/tests/useMutationState.test.ts 覆盖了三个关键行为可作为使用时的契约依据按 key status 筛选调用mutate(variables)后useMutationState({ filters: { mutationKey: key, status: pending }, select: (m) m.state.variables })的.value等于[variables]第 19-36 行。无 filters 时返回全部不带任何参数时mutationState.value[0]?.variables即最近一次 mutation 的 variables第 38-54 行。getter 选项的响应式修改ref驱动的 filters 后结果自动更新第 56-80 行。七、使用注意与常见陷阱必须在 setup 作用域内调用useMutationState依赖onScopeDispose清理订阅。在script setup、setup()或 effect scope 中调用是安全的在普通函数/事件回调中调用会漏掉清理逻辑长期累积可能造成内存泄漏。返回数组随调用次数增长同 key 的 mutation 每mutate一次就会多一条记录在gcTime内。取最新务必用[length - 1]不要假设数组长度恒为 1。默认是模糊匹配 keyfilters.mutationKey不传exact: true时按前缀匹配可能误伤同前缀的其它 mutation。只读返回结果是ReadonlyRef...不能通过修改它反向影响 mutation 状态要控制 mutation 请使用useMutation的mutate/mutateAsync。与useIsMutating的关系useIsMutating可视为useMutationState的pending计数封装如果你只需要有几个在跑用 useIsMutating 更轻量。结语useMutationState是 Vue Query 中少有的面向全局 mutation 状态的观测入口一个组合式函数即可完成筛选 → 转换 → 响应式订阅全流程。理解它之后你不仅能优雅地实现多 mutation 全局进度条批量提交状态聚合追踪最新一次变更结果等场景也能借此一窥MutationCache事件驱动的架构设计——这也是它区别于useMutation的核心价值所在。【免费下载链接】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),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门