背景与问题界定
随着 Vue3 的全面普及,Composition API 已经成为中大型项目的主要开发范式。然而,许多团队在使用过程中暴露出两个典型问题:一是组合函数的跨组件复用缺乏统一规范,导致同一业务逻辑在不同组件中出现三四种不同的封装风格;二是复杂交互场景下的状态管理陷入面条式代码——多个 ref 和 reactive 散布在 setup 中,状态转换路径隐晦难测,尤其是在多步骤表单、长连接握手和异步任务编排等场景中尤为突出。这些问题本质上是 Composition API 提供的灵活性带来了设计约束的缺失,当团队规模超过 5 人时,维护成本呈指数级上升。我们需要一套可落地、可审阅的设计模式来解决这些工程痛点。
目标拆解与工程约束
- 组合函数的可组合性与语义清晰:每个组合函数应保持单一职责,函数名体现用途,返回值使用
readonly和toRefs控制可变性暴露,禁止在函数内部意外修改外部作用域。 - 状态转换的可追溯性与不可变快照:复杂状态机场景必须采用显式状态定义,禁止隐式地在多个 ref 之间通过
watch联动产生状态迁移,所有合法转换路径需声明在状态表中。 - 与 Pinia/Vuex 的职责边界:组合函数负责局部 UI 逻辑和设备 API 封装,全局跨组件数据流向 Pinia store 管理,避免在组合函数中引用全局 store 造成紧耦合。
- 单元测试友好:组合函数应纯化副作用,API 请求、定时器和 DOM 事件通过可注入的适配器封装,确保
mount时无需真正初始化浏览器环境即可完成逻辑验证。
方案设计
核心思路是将 Composition API 的使用提升到设计模式层面,不再把 setup 看作一个可以随意书写命令式逻辑的地方。我们定义了三层模式体系:基础组合函数(Primitive Composables)、业务组合函数(Business Composables) 和 有限状态机(State Machine)。
基础组合函数负责单一浏览器 API 或通用工具的封装,例如 useLocalStorage、useMediaQuery。这类函数具有纯函数式的接口——接收配置型参数,返回响应式状态和操作方法,不做任何业务依赖。业务组合函数则编排一个完整的业务领域逻辑,比如 useOrderFlow,它内部组合多个基础组合函数,暴露统一的 state、actions 和 effects。
当业务组合函数的内部状态转换超过 3 个分支时,强制采用有限状态机模式。借助 @vueuse/core 的 useMachine 或自行实现转换表,将每个状态(idle / loading / success / error)和允许的切换路径显式声明。例如一个异步提交流程的状态机:
const states = {
idle: { transitions: ['submit'] },
submitting: { transitions: ['success', 'error'] },
success: { transitions: ['reset'] },
error: { transitions: ['retry', 'reset'] }
}
const { state, can, send } = useStateMachine(states)
这种显式声明的状态机不仅消除了非法状态转换,还天然支持开发工具的日志记录和时间旅行调试。
对于跨组件的组合函数共享,我们不采用 provide/inject 直接传递 ref(这会导致来源不明确),而是通过一个组合函数工厂工厂模式——createSharedComposable——维护一个 WeakMap 实例池,确保同一个 Key 在全局只初始化一次,同时不造成内存泄漏。
实施路径与关键决策
- 确立组合函数命名规范:所有组合函数以
use开头,返回值采用{ state, actions, effects }三元组结构,禁止返回零散的多个变量。 - 引入状态机模式的门禁检查:在 Code Review 阶段,任何含 3 个以上手动
if/switch状态分支的逻辑块,必须重构为有限状态机。 - 编写组合函数模板与代码片段:在 VS Code 中为三类模式提供 snippet,降低入门门槛,确保团队输出一致性。
- 建立组合函数的单元测试夹具:基于
@vue/test-utils+vue-demi,提供一个compose辅助函数,自动在测试中创建临时组件并挂载组合函数。
验证指标与可持续迭代
通过三个维度验证成效:一是组合函数的单测覆盖率不低于 90%,特别是状态机转换表中每一个分支均需独立用例覆盖;二是业务组合函数在 code review 中的平均驳回率从实施前的 40% 降至 15% 以下;三是开发者在排查复杂交互 bug 时,优先检查状态机日志而非手动断点——这个行为转变是真正内化的标志。后续每季度检视一次模式库,淘汰不再适用的组合函数,补充新涌现的模式。
工程落地思考
Composition API 的设计哲学是"组合优于继承",但组合本身也需要规范和约束才能产生真正的生产力。从组合函数到有限状态机的演进路径,本质上是一个给灵活工具加装护栏的过程。我们不应将模式当作教条,而应将其视为团队沟通的共同语言。当团队成员在讨论中说"这个逻辑需要走一次 submitting → error → retry",而不是"先改一下那个 ref 再 watch 一下",模式的价值就已显现——它让思考的复杂度从实现细节转移到结构层面。