Composition API
Vue 3 用函数组织组件逻辑的一组 API
它解决了什么问题?
Options API 按 data、methods、computed、watch 等选项组织代码。组件较大时,同一业务逻辑容易分散在多个选项中;复用逻辑通常还要依赖 Mixins,而 Mixins 存在数据来源不清晰、命名冲突等问题。
Composition API 允许将同一业务关注点的状态、计算属性、方法和生命周期放在一起,并进一步抽取成组合式函数(Composable)。
主要优势
- 按业务逻辑聚合:相关状态、方法和副作用可以放在一起
- 逻辑复用清晰:Composable 的输入、输出和依赖都可以显式表达
- TypeScript 友好:主要使用普通变量和函数,类型推导更自然
- 更灵活的代码拆分:可按功能拆分模块,也有利于测试
- 支持 Tree Shaking:未使用的独立 API 更容易被构建工具移除,但不代表业务包体积一定更小
Composition API 并不是 Options API 的替代品。简单组件使用 Options API 仍然合理;复杂组件、逻辑复用较多或 TypeScript 项目通常更适合 Composition API。
setup()
setup() 是 Composition API 的入口,在组件创建过程中、Options API 的大多数选项处理之前执行。
props
第一个参数 props 是一个只读的响应式对象。不能直接修改它,也不能随意解构,否则可能丢失响应式关联。
如果只读取一次、不需要追踪后续变化,普通解构没有问题。Vue 3.5+ 的 <script setup> 还支持响应式 Props 解构,详见下文。
context
第二个参数是 setup 上下文,可以安全解构:
context 本身不是响应式对象。attrs 会保持最新值,但不能通过 watch() 追踪其属性变化;如果需要响应变化,应使用相应的 prop,或者在 onUpdated() 中处理。
返回值
setup() 通常返回一个对象,对象中的属性和方法可以在模板中使用。模板会自动解包顶层 ref,因此模板中不需要写 .value。
setup() 也可以直接返回渲染函数,此时不能再同时返回供模板使用的对象。
为什么 setup() 中没有 this?
执行 setup() 时,Options API 中的 data、computed 和 methods 等内容还没有初始化完成,因此不能通过组件公开实例的 this 访问它们。Vue 有意让 Composition API 使用变量、函数和参数显式组织依赖。
不要在 setup() 中混用 this:
反过来,Options API 可以通过 this 访问 setup() 返回的属性,但新代码不建议依赖这种混合方式。
<script setup>
<script setup> 是单文件组件中使用 Composition API 的推荐语法。代码会被编译为组件的 setup() 内容,顶层变量、函数和导入的组件可以直接在模板中使用。
编译宏
defineProps、defineEmits、defineExpose 等是编译宏,只能在 <script setup> 中使用,不需要从 vue 导入。
常用宏包括:
Props 响应式解构
在 Vue 3.5+ 中,<script setup> 对同一代码块中 defineProps() 解构出的变量进行响应式转换:
在 Vue 3.4 及更早版本中,直接解构不会保持响应式,应使用 props.title,或者通过 toRefs(props) 解构。维护旧版本项目时要先确认 Vue 版本。
响应式状态与副作用
Composition API 常用以下几类能力:
ref()、reactive():声明响应式状态computed():声明派生状态watch()、watchEffect():处理响应式副作用onMounted()、onUpdated()、onUnmounted():注册生命周期逻辑
具体区别可阅读响应式 API、computed 与 watch和Vue 生命周期。
生命周期钩子必须在 setup() 同步执行期间注册,才能与当前组件实例关联:
如何设计 Composable?
Composable 是使用 Composition API 封装和复用有状态逻辑的函数,通常以 use 开头,例如 useMouse()、useFetch()。
onScopeDispose() 可以让清理逻辑跟随调用方的响应式作用域销毁。它比只能依赖组件卸载的写法更容易复用。
设计 Composable 时应注意:
- 输入参数可以接受普通值、ref 或 getter 时,要明确并统一处理
- 返回 ref 或包含 ref 的普通对象,方便调用方解构后仍保持响应式
- 在函数内部完成定时器、监听器和请求等副作用的清理
- 避免修改调用方未授权的状态,让数据流保持清晰
- 不要过度拆分;只使用一次且很简单的逻辑可以留在组件内
Composition API 与 Mixins
Composable 复用的是逻辑,不是组件模板。需要同时复用 UI 结构时,应考虑组件或插槽。
常见误区
Composition API 等于 Hooks 吗?
不完全等同。它的组合式函数在使用体验上类似 React Hooks,但 Vue 依靠响应式系统追踪依赖,不依赖固定的调用顺序,也没有 React Hooks 的条件调用限制。
所有状态都应该使用 reactive() 吗?
不是。ref() 可用于任意类型,也便于传递和替换;reactive() 适合将相关对象状态组织在一起。选择方式详见响应式 API。
setup() 等于 created 吗?
只能近似理解为都处于组件创建阶段,不能认为两者完全等价。setup() 的执行时机更早,并承担状态声明、逻辑组合和生命周期注册等职责。
Composable 可以在任意位置调用吗?
纯响应式逻辑可以在普通模块中使用;依赖生命周期、provide/inject 或当前组件实例的 Composable,通常必须在 setup() 同步执行期间调用。
面试总结
Composition API 是 Vue 3 用函数组织组件逻辑的一组 API。它通过 setup() 或 <script setup> 声明响应式状态、派生状态、副作用和生命周期,并可将有状态逻辑抽取为 Composable。
它的核心价值不是“代码更短”,而是让同一业务逻辑聚合、依赖来源明确、逻辑更容易复用和测试。相较 Mixins,Composable 具有显式输入输出、较少命名冲突和更好的 TypeScript 推导。实际开发中应根据组件复杂度选择 Composition API 或 Options API,并注意响应式解构、资源清理和 Vue 版本差异。

