news 2026/9/10 13:12:04

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

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
TanStack Query(Svelte)`MutationStateOptions` 类型全面解析:用 `useMutationState` 精准订阅 Mutation 状态

TanStack Query(Svelte)MutationStateOptions类型全面解析:用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/query

MutationStateOptions是 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 Mutation<any, any, any, any> = MutationTypeFromResult<TResult>, > = { 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 = MutationState

TResult表示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的取值是MutationStatus'pending' | 'success' | 'error'等),submittedAt是提交时间戳。当select被提供时,TResult会被具体化为select的返回类型。

TMutation:由TResult反推的 Mutation 实例类型

TMutation extends Mutation<any, any, any, any> = MutationTypeFromResult<TResult>

TMutationselect回调里mutation参数的类型。它默认通过MutationTypeFromResult<TResult>这个条件类型从TResult反推出来,定义在 packages/svelte-query/src/types.ts:

export type MutationTypeFromResult<TResult> = [TResult] extends [ MutationState< infer TData, infer TError, infer TVariables, infer TOnMutateResult >, ] ? Mutation<TData, TError, TVariables, TOnMutateResult> : Mutation

这里的核心技巧是:

  • 如果TResult本身是MutationState<TData, TError, TVariables, TOnMutateResult>(或者可以从中推断出四个泛型),则TMutation被收紧为携带同样类型参数的Mutation<TData, TError, TVariables, TOnMutateResult>
  • 否则退化为兜底的Mutation(即Mutation<any, any, any, any>)。

由于TResult的默认值就是MutationState,所以默认情况下select拿到的mutation就是泛型完整的Mutation<TData, TError, TVariables, TOnMutateResult>,在 TS 严格模式下依然能拿到mutation.state.variablesmutation.state.data的精确类型,而不是any。这是保证useMutationState全链路类型安全的关键一环。

两个可选属性详解

filters?: MutationFilters—— 筛选维度

MutationFilters定义在 packages/query-core/src/utils.ts:

export interface MutationFilters< TData = unknown, TError = DefaultError, TVariables = unknown, TOnMutateResult = unknown, > { /** 是否精确匹配 mutation key(默认 false,见下文 findAll 说明) */ exact?: boolean /** 用谓词函数自由筛选 mutation */ predicate?: ( mutation: Mutation<TData, TError, TVariables, TOnMutateResult>, ) => boolean /** 按 mutation key 筛选(支持前缀匹配) */ mutationKey?: TuplePrefixes<MutationKey> /** 按状态筛选: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.statemutation.options等任意字段做自定义判断。

select?: (mutation: TMutation) => TResult—— 数据投影

optional select: (mutation) => TResult;

select接收一个匹配到的Mutation实例(而非MutationState!),返回你想要的任意形状TResult。也就是说,select里可以访问mutation.state,也能访问mutation.optionsmutation.mutationId等实例级信息。

它在底层的作用等价于数组的.map

mutationCache .findAll(options.filters) .map((mutation) => options.select(mutation))

不传select时,返回的每一项就是mutation.state(即默认TResult = MutationState)。

源码级原理:useMutationState如何消费这两个选项

useMutationState的实现(packages/svelte-query/src/useMutationState.svelte.ts)展示了filtersselect在运行时被如何使用:

export function useMutationState< TResult = MutationState, TMutation extends Mutation<any, any, any, any> = MutationTypeFromResult<TResult>, >( options: MutationStateOptions<TResult, TMutation> = {}, queryClient?: QueryClient, ): Array<TResult> { 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 }

核心步骤拆解:

  1. 取缓存useQueryClient(queryClient).getMutationCache()拿到当前 QueryClient 全局唯一的 MutationCache(可用第二参数指定自定义 QueryClient,否则取最近 context 中的那个)。
  2. 首次计算getResult立即执行一次,得到初始快照:
    function getResult<TResult, TMutation>( mutationCache: MutationCache, options: MutationStateOptions<TResult, TMutation>, ): Array<TResult> { return mutationCache .findAll(options.filters) // ① 用 filters 筛选 .map( (mutation): TResult => (options.select // ② 用 select 投影 ? options.select(mutation as TMutation) : mutation.state) as TResult, // ③ 缺省时取 state ) }
  3. 响应式订阅:在$effect中订阅mutationCache。每次有任何 mutation 发生变化(新增、pending、success、error、GC 移除等)都会触发重算。
  4. 稳定更新:重算结果用replaceEqualDeep(来自@tanstack/query-core)与当前result做结构共享比较;只有内容真正变化时才原地更新$state数组,从而避免无关的 Svelte 重渲染。

这意味着useMutationState观察的是全局 MutationCache,因此能看到"由其他组件、其他 hook 实例创建、甚至已经卸载的 mutation"——这正是文档注释(packages/svelte-query/src/useMutationState.svelte.ts)强调的能力,也是它与createMutation(只关心单个 mutation)最本质的区别。

底层筛选:MutationCache.findAllmatchMutation

filters最终被交给 MutationCache 的方法,见 packages/query-core/src/mutationCache.ts:

findAll(filters: MutationFilters = {}): Array<Mutation> { return this.getAll().filter((mutation) => matchMutation(filters, mutation)) }

matchMutation会依次对mutationKey(前缀或精确)、exactstatuspredicate做匹配。注意这里与 Query 的find(mutationCache.ts)不同:find默认exact: true,而findAll默认exact: false(即默认按前缀匹配 key)。了解这个差异,能避免"为什么传['posts']却把['posts', 'x']也筛进来了"的困惑。

实战示例:三种高频用法

以下示例均取自useMutationState的官方 JSDoc(packages/svelte-query/src/useMutationState.svelte.ts),可直接在 Svelte 5 组件中使用。

示例一:获取所有进行中 mutation 的 variables

<script lang="ts"> 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的类型是Array<unknown>(由TResult推导)。

示例二:通过mutationKey获取特定 mutation 的成功数据

<script lang="ts"> 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>

注意mutationKeystatus: 'success'组合使用:mutationKey定位业务线,status排除掉 pending 与 error 的条目。

示例三:取"最新一次"成功变更的数据

<script lang="ts"> 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虽然只有filtersselect两个字段,却是useMutationState的"筛选 + 投影"双引擎:

维度字段作用
筛选filters交给MutationCache.findAllmatchMutation,支持mutationKey(前缀匹配)、exactstatuspredicate
投影selectMutation实例转换为TResult,缺省时返回mutation.state
类型TResult/TMutation通过MutationTypeFromResult条件类型反推select参数类型,保证全链路类型安全

结合 MutationTypeFromResult 与MutationState(packages/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),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/10 13:09:38

锥齿轮丝杆升降机效率优化六大关键因素

1. 锥齿轮丝杆升降机效率影响因素解析作为一名在机械传动领域摸爬滚打十二年的工程师&#xff0c;我处理过上百台锥齿轮丝杆升降机的故障案例。今天想和大家聊聊这个看似简单却暗藏玄机的问题——哪些因素会直接影响升降机的传动效率&#xff1f;通过实测数据和现场经验&#x…

作者头像 李华
网站建设 2026/9/10 13:08:52

Qt Q3D三维可视化模块化实战:从OpenGL配置到颜色映射

简介&#xff1a;本资源是一套面向Qt中级开发者与三维可视化学习者的Q3D图表开发实战源码集&#xff0c;涵盖散点图、柱状图、曲面图三大核心图表类型的完整Demo实现&#xff0c;并深入解析曲面图颜色样式配置&#xff0c;助力快速掌握Qt 3D图表模块的工程化集成与定制技巧。压…

作者头像 李华
网站建设 2026/9/10 13:02:58

SpringBoot+Vue酒店管理系统全栈开发实践

1. 项目概述&#xff1a;SpringBootVue酒店管理系统全栈实践酒店管理系统作为现代服务业数字化转型的核心工具&#xff0c;其技术选型与实现方案直接影响运营效率。这套基于SpringBootVue的全栈解决方案&#xff0c;完美融合了后端稳定性和前端交互体验&#xff0c;为中小型酒店…

作者头像 李华