TanStack Query(Svelte)`MutationStateOptions` 类型全面解析:用 `useMutationState` 精准订阅 Mutation 状态

发布时间:2026/9/10 13:12:18
TanStack Query(Svelte)`MutationStateOptions` 类型全面解析:用 `useMutationState` 精准订阅 Mutation 状态 TanStack QuerySvelteMutationStateOptions类型全面解析用useMutationState精准订阅 Mutation 状态【免费下载链接】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/queryMutationStateOptions是 TanStack Query 在 Svelte 框架适配层tanstack/svelte-query中为useMutationState定义的核心选项类型。它通过filters从全局 MutationCache 中筛选目标 mutation再通过可选的select把原始MutationState投影为组件真正需要的返回值。读完本文你将掌握该类型的完整签名、两个泛型参数的推导逻辑、底层过滤与订阅机制并能直接写出可运行的 Svelte 5 代码来追踪进行中的请求已保存的数据最新一次成功的变更等真实场景。类型签名总览在 packages/svelte-query/src/types.ts 中MutationStateOptions被定义为一个只有两个可选属性的对象类型/** Options for useMutationState */ export type MutationStateOptions TResult MutationState, TMutation extends Mutationany, any, any, any MutationTypeFromResultTResult, { filters?: MutationFilters select?: (mutation: TMutation) TResult }对应的 API 参考文档见 docs/framework/svelte/reference/type-aliases/MutationStateOptions.md。它是useMutationState的入参类型而useMutationState的完整实现位于 packages/svelte-query/src/useMutationState.svelte.ts。从签名可以看出MutationStateOptions本身极其精简——它不直接存储任何 mutation 数据而是描述如何从 MutationCache 里挑选并转换数据。所有筛选逻辑委托给filtersMutationFilters所有转换逻辑委托给select。泛型参数从结果反推 Mutation 类型的类型体操TResult返回值投影类型TResult MutationStateTResult表示useMutationState最终返回数组中每一项的类型。默认值就是MutationState——即未提供select时函数直接返回每个匹配 mutation 的state快照。MutationState本身定义在 packages/query-core/src/mutation.ts字段如下export interface MutationState TData unknown, TError DefaultError, TVariables unknown, TOnMutateResult unknown, { context: TOnMutateResult | undefined data: TData | undefined error: TError | null failureCount: number failureReason: TError | null isPaused: boolean status: MutationStatus variables: TVariables | undefined submittedAt: number }其中status的取值是MutationStatuspending | success | error等submittedAt是提交时间戳。当select被提供时TResult会被具体化为select的返回类型。TMutation由TResult反推的 Mutation 实例类型TMutation extends Mutationany, any, any, any MutationTypeFromResultTResultTMutation是select回调里mutation参数的类型。它默认通过MutationTypeFromResultTResult这个条件类型从TResult反推出来定义在 packages/svelte-query/src/types.tsexport type MutationTypeFromResultTResult [TResult] extends [ MutationState infer TData, infer TError, infer TVariables, infer TOnMutateResult , ] ? MutationTData, TError, TVariables, TOnMutateResult : Mutation这里的核心技巧是如果TResult本身是MutationStateTData, TError, TVariables, TOnMutateResult或者可以从中推断出四个泛型则TMutation被收紧为携带同样类型参数的MutationTData, TError, TVariables, TOnMutateResult否则退化为兜底的Mutation即Mutationany, any, any, any。由于TResult的默认值就是MutationState所以默认情况下select拿到的mutation就是泛型完整的MutationTData, TError, TVariables, TOnMutateResult在 TS 严格模式下依然能拿到mutation.state.variables、mutation.state.data的精确类型而不是any。这是保证useMutationState全链路类型安全的关键一环。两个可选属性详解filters?: MutationFilters—— 筛选维度MutationFilters定义在 packages/query-core/src/utils.tsexport interface MutationFilters TData unknown, TError DefaultError, TVariables unknown, TOnMutateResult unknown, { /** 是否精确匹配 mutation key默认 false见下文 findAll 说明 */ exact?: boolean /** 用谓词函数自由筛选 mutation */ predicate?: ( mutation: MutationTData, TError, TVariables, TOnMutateResult, ) boolean /** 按 mutation key 筛选支持前缀匹配 */ mutationKey?: TuplePrefixesMutationKey /** 按状态筛选pending / success / error */ status?: MutationStatus }各字段的实际作用mutationKey按 key 过滤。注意它支持TuplePrefixes即传入的 key 会按前缀语义匹配例如[posts]可以匹配[posts, detail]。这是useMutationState最常用的过滤方式用于跨组件定位某条业务线如所有发帖相关的 mutation的全部 mutation 实例。exact布尔值表示是否要求mutationKey完全相等而非前缀匹配。在mutationCache.findAll内部exact的默认行为见下节源码。status按pending | success | error状态过滤例如只想拿正在提交中的 mutation。predicate最强大的兜底手段——一个接收Mutation实例、返回布尔值的函数可对mutation.state、mutation.options等任意字段做自定义判断。select?: (mutation: TMutation) TResult—— 数据投影optional select: (mutation) TResult;select接收一个匹配到的Mutation实例而非MutationState返回你想要的任意形状TResult。也就是说select里可以访问mutation.state也能访问mutation.options、mutation.mutationId等实例级信息。它在底层的作用等价于数组的.mapmutationCache .findAll(options.filters) .map((mutation) options.select(mutation))不传select时返回的每一项就是mutation.state即默认TResult MutationState。源码级原理useMutationState如何消费这两个选项useMutationState的实现packages/svelte-query/src/useMutationState.svelte.ts展示了filters与select在运行时被如何使用export function useMutationState TResult MutationState, TMutation extends Mutationany, any, any, any MutationTypeFromResultTResult, ( options: MutationStateOptionsTResult, TMutation {}, queryClient?: QueryClient, ): ArrayTResult { const mutationCache useQueryClient(queryClient).getMutationCache() const result $state(getResult(mutationCache, options)) $effect(() { const unsubscribe mutationCache.subscribe(() { const nextResult replaceEqualDeep( result, getResult(mutationCache, options), ) if (result ! nextResult) { result.splice(0, result.length, ...nextResult) } }) return unsubscribe }) return result }核心步骤拆解取缓存useQueryClient(queryClient).getMutationCache()拿到当前 QueryClient 全局唯一的 MutationCache可用第二参数指定自定义 QueryClient否则取最近 context 中的那个。首次计算getResult立即执行一次得到初始快照function getResultTResult, TMutation( mutationCache: MutationCache, options: MutationStateOptionsTResult, TMutation, ): ArrayTResult { return mutationCache .findAll(options.filters) // ① 用 filters 筛选 .map( (mutation): TResult (options.select // ② 用 select 投影 ? options.select(mutation as TMutation) : mutation.state) as TResult, // ③ 缺省时取 state ) }响应式订阅在$effect中订阅mutationCache。每次有任何 mutation 发生变化新增、pending、success、error、GC 移除等都会触发重算。稳定更新重算结果用replaceEqualDeep来自tanstack/query-core与当前result做结构共享比较只有内容真正变化时才原地更新$state数组从而避免无关的 Svelte 重渲染。这意味着useMutationState观察的是全局 MutationCache因此能看到由其他组件、其他 hook 实例创建、甚至已经卸载的 mutation——这正是文档注释packages/svelte-query/src/useMutationState.svelte.ts强调的能力也是它与createMutation只关心单个 mutation最本质的区别。底层筛选MutationCache.findAll与matchMutationfilters最终被交给 MutationCache 的方法见 packages/query-core/src/mutationCache.tsfindAll(filters: MutationFilters {}): ArrayMutation { return this.getAll().filter((mutation) matchMutation(filters, mutation)) }matchMutation会依次对mutationKey前缀或精确、exact、status、predicate做匹配。注意这里与 Query 的findmutationCache.ts不同find默认exact: true而findAll默认exact: false即默认按前缀匹配 key。了解这个差异能避免为什么传[posts]却把[posts, x]也筛进来了的困惑。实战示例三种高频用法以下示例均取自useMutationState的官方 JSDocpackages/svelte-query/src/useMutationState.svelte.ts可直接在 Svelte 5 组件中使用。示例一获取所有进行中 mutation 的 variablesscript langts import { useMutationState } from tanstack/svelte-query const pendingVariables useMutationState({ filters: { status: pending }, select: (mutation) mutation.state.variables, }) /script {pendingVariables.length} posts saving...这里filters: { status: pending }只筛出正在执行的重试/变更select把每一项投影成variables因此pendingVariables的类型是Arrayunknown由TResult推导。示例二通过mutationKey获取特定 mutation 的成功数据script langts import { createMutation, useMutationState } from tanstack/svelte-query const mutationKey [posts] // 某个我们想跟踪状态的 mutation const mutation createMutation(() ({ mutationKey, mutationFn: createPosts, })) const savedPosts useMutationState({ // 这个 key 必须与上方 mutation 的 key 一致 filters: { mutationKey, status: success }, select: (mutation) mutation.state.data, }) /script button onclick{() mutation.mutate([New Post])} Create post ({savedPosts.length} saved so far) /button注意mutationKey与status: success组合使用mutationKey定位业务线status排除掉 pending 与 error 的条目。示例三取最新一次成功变更的数据script langts import { useMutationState } from tanstack/svelte-query const savedPosts useMutationState({ filters: { mutationKey: [posts], status: success }, select: (mutation) mutation.state.data, }) const latestSavedPost $derived(savedPosts[savedPosts.length - 1]) /script {latestSavedPost ? Saved : Nothing saved yet}原理每次调用mutate都会向 MutationCache 写入一条新记录并在gcTime默认 5 分钟后才会被回收。因此useMutationState返回的数组按时间顺序累积取最后一项就是最近一次满足筛选条件的 mutation——这是文档与源码共同印证的行为见 packages/svelte-query/src/useMutationState.svelte.ts。小结MutationStateOptions虽然只有filters与select两个字段却是useMutationState的筛选 投影双引擎维度字段作用筛选filters交给MutationCache.findAll→matchMutation支持mutationKey前缀匹配、exact、status、predicate投影select将Mutation实例转换为TResult缺省时返回mutation.state类型TResult/TMutation通过MutationTypeFromResult条件类型反推select参数类型保证全链路类型安全结合 MutationTypeFromResult 与MutationStatepackages/query-core/src/mutation.ts你可以在 Svelte 5 中零成本地订阅全局 mutation 状态无需为每个 mutation 单独维护本地变量——这正是 TanStack Query 服务端状态管理中跨组件、跨生命周期观测变更的核心能力。【免费下载链接】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),仅供参考