先记住这个答案
mixin 把多个来源的选项合并到组件实例中,容易造成属性来源不清楚、名称冲突和通过 this 字段进行的隐式依赖。组合式函数把复用逻辑表达为显式调用,状态从返回值取得,依赖通过参数传入,冲突时可以局部重命名。这样更容易追踪和独立验证。迁移并不是把文件改名加 use 前缀,还要保留原有生命周期、状态范围与公开行为,并清理原先隐藏的跨 mixin 关系。
- 显式调用和返回值让状态来源更容易查找
- 局部重命名缓解实例命名空间冲突
- 函数参数能表达依赖,但仍需检查状态共享和副作用
属性合并为什么让排查变困难
一个组件同时混入筛选、分页和请求逻辑时,this.loading 可能来自多个文件,阅读使用点很难确认哪个来源真正生效。重名字段还涉及选项合并规则,某次新增 mixin 就可能改变旧字段行为,而调用组件本身看不出明显差异。
改成分别调用 useFilter、usePagination 和 useRequest 后,返回值来源可以在 setup 中直接看到。遇到同名 loading,可以重命名成列表加载与详情加载,或者重新设计接口;不需要把所有功能都挤进组件实例的同一个属性命名空间。
把隐藏依赖转成参数和产物
旧分页 mixin 可能默认另一个 mixin 已经提供 fetchList 方法,只有在运行到某个路径时才发现依赖缺失。组合式函数可以显式接收加载函数、请求键或筛选状态,调用处展示了它究竟依赖谁,测试时也能提供替代实现。
依赖显式之后,还可以判断循环关系是否合理。例如筛选变化重置页码,页码变化发请求,不应再通过多个隐藏 watcher 互相写回形成循环。组合式函数只是让关系更容易表达,真正的更新顺序和所有权仍需要重新梳理。
迁移时保留行为而不是机械搬运
mixin 中的生命周期钩子和数据初始化遵循原来的合并与执行规则,搬进函数后要确认何时调用、调用几次以及何时清理。把原本每实例创建的状态移到模块外,会意外变成共享状态;忘记注册清理则可能使监听器在组件卸载后继续存在。
适合先挑一个边界清楚的功能迁移,列出输入、返回状态、动作和资源寿命,再用已有场景验证外部行为。若功能同时需要复用视觉布局,组件或插槽仍可能更合适;组合式函数主要复用逻辑,不能替代所有 UI 组合方式。
容易答错的地方
- 改成 use 函数后依赖自然就清楚了
- 如果仍从全局状态偷偷读取数据或修改外部对象,隐式耦合依然存在,应明确输入和更新路径。排查“Vue 组合式函数与 mixin 来源冲突隐式依赖对比”时还要核对输入、版本和执行顺序,并用反例确认修复后的边界。
- mixin 迁移只要复制代码即可
- 生命周期时机、状态作用域和选项合并行为可能变化,需要按真实行为验收。排查“Vue 组合式函数与 mixin 来源冲突隐式依赖对比”时还要核对输入、版本和执行顺序,并用反例确认修复后的边界。
面试官还会怎么问?
两个 composable 返回同名字段怎么办?
可以在调用处解构重命名,或通过分组对象表达来源;同时考虑名字是否过于泛化。针对“Vue 组合式函数与 mixin 来源冲突隐式依赖对比”,还应保留最小复现、预期结果和失败路径,避免只凭一次现象下结论。
旧项目必须一次性删除所有 mixin 吗?
不必,优先处理造成维护问题的功能,逐步迁移并保留已验证行为,避免大范围同时改变多个依赖。针对“Vue 组合式函数与 mixin 来源冲突隐式依赖对比”,还应保留最小复现、预期结果和失败路径,避免只凭一次现象下结论。
组合式函数适合复用一整块界面吗?
纯逻辑复用适合 composable,包含布局和交互结构的复用通常还需要组件或插槽。针对“Vue 组合式函数与 mixin 来源冲突隐式依赖对比”,还应保留最小复现、预期结果和失败路径,避免只凭一次现象下结论。
参考资料
示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。