本文详细解析 Vue 3 的 Composition API 设计思想与核心用法,助你构建更灵活可维护的 Vue 应用

为什么需要 Composition API?

在 Vue 2 中,我们使用 Options API 组织组件代码:

export default {
  data() {
    return { count: 0 }
  },
  methods: {
    increment() {
      this.count++
    }
  },
  mounted() {
    console.log('组件已挂载')
  }
}  

随着组件复杂度增加,Options API 暴露了三个主要问题:

  1. 逻辑关注点碎片化 - 相关功能被拆分到不同选项
  2. 逻辑复用困难 - Mixins 存在命名冲突和来源不清晰问题
  3. 类型支持有限 - 对 TypeScript 支持不够友好

Composition API 核心概念

1. setup() 函数

import { ref, onMounted } from 'vue'

export default {
  setup() {
    // 状态声明
    const count = ref(0)
    
    // 方法定义
    function increment() {
      count.value++
    }
    
    // 生命周期钩子
    conMounted(() => {
      console.log('组件已挂载')
    })
    
    // 暴露给模板
    return { count, increment }
  }
}

setup() 是 Composition API 的入口点:

  • 在组件创建之前执行
  • 接收 props 和 context 参数
  • 返回对象中的属性将暴露给模板使用

2. 响应式系统核心

ref()

const count = ref(0)
console.log(count.value) // 0
count.value = 1
  • 用于创建基础类型的响应式数据
  • 通过 .value 访问实际值

reactive()

const state = reactive({
  count: 0,
  user: { name: 'John' }
})
state.count = 1
  • 创建对象的响应式代理
  • 嵌套对象自动深度响应

3.计算属性

const doubleCount = computed(() => count.value * 2)

4. 生命周期钩子

Options API Composition API
beforeCreate 不需要(在setup中)
created 不需要(在setup中)
beforeMount onBeforeMount
mounted onMounted
beforeUpdate onBeforeUpdate
updated onUpdated
beforeUnmount onBeforeUnmount
unmounted onUnmounted

逻辑复用:自定义组合函数

// useCounter.js
import { ref } from 'vue'

export default function useCounter(initialValue = 0) {
  const count = ref(initialValue)
  
  function increment() {
    count.value++
  }
  
  function decrement() {
    count.value--
  }
  
  return {
    count,
    increment,
    decrement
  }
}

在组件中使用:

import useCounter from './useCounter'

export default {
  setup() {
    const { count, increment } = useCounter(10)
    
    return { count, increment }
  }
}
相比 Mixins 的优势:

- 明确的功能来源
- 无命名空间冲突
- 参数传递灵活
- 类型推断友好

响应式原理剖析

Vue 3 使用 Proxy 替代 Object.defineProperty:

const reactiveHandler = {
  get(target, key) {
    track(target, key) // 依赖追踪
    return Reflect.get(target, key)
  },
  set(target, key, value) {
    Reflect.set(target, key, value)
    trigger(target, key) // 触发更新
    return true
  }
}

function reactive(obj) {
  return new Proxy(obj, reactiveHandler)
}

优势:

  • 支持数组索引修改
  • 支持动态添加属性
  • 性能更优
  • 支持 Map/Set 等集合类型