Composition API vs Options API

Vue3 两种组件写法的对比与选择

问题

Vue3 提供了 Composition API 和 Options API 两种组件写法,它们有什么区别?setuprefreactivetoRef 分别是什么?

解答

Options API

传统的 Vue2 写法,按选项类型组织代码:

export default {
  data() {
    return {
      count: 0,
      user: {
        name: 'Tom',
        age: 18
      }
    }
  },
  computed: {
    doubleCount() {
      return this.count * 2
    }
  },
  methods: {
    increment() {
      this.count++
    }
  },
  mounted() {
    console.log('组件挂载完成')
  }
}

Composition API

Vue3 新增的写法,按逻辑功能组织代码:

<script setup>
import { ref, reactive, computed, onMounted, toRef, toRefs } from 'vue'

// ref: 创建基本类型的响应式数据
const count = ref(0)

// reactive: 创建对象类型的响应式数据
const user = reactive({
  name: 'Tom',
  age: 18
})

// computed: 计算属性
const doubleCount = computed(() => count.value * 2)

// 方法直接定义
function increment() {
  count.value++ // ref 需要 .value 访问
}

// toRef: 从 reactive 对象中提取单个属性,保持响应式
const name = toRef(user, 'name')

// toRefs: 解构 reactive 对象,保持每个属性的响应式
const { age } = toRefs(user)

// 生命周期
onMounted(() => {
  console.log('组件挂载完成')
})
</script>

ref vs reactive

import { ref, reactive } from 'vue'

// ref: 适合基本类型,也可以包装对象
const count = ref(0)
const obj = ref({ a: 1 })

console.log(count.value)     // 0
console.log(obj.value.a)     // 1

// reactive: 只能用于对象类型
const state = reactive({
  count: 0,
  list: []
})

console.log(state.count)     // 0,不需要 .value

toRef 和 toRefs 的作用

import { reactive, toRef, toRefs } from 'vue'

const user = reactive({
  name: 'Tom',
  age: 18
})

// 错误:直接解构会丢失响应式
const { name } = user // name 不是响应式的

// 正确:使用 toRef 提取单个属性
const name = toRef(user, 'name') // name 是响应式的

// 正确:使用 toRefs 解构整个对象
const { name, age } = toRefs(user) // 都是响应式的

// 修改会同步到原对象
name.value = 'Jerry'
console.log(user.name) // 'Jerry'

逻辑复用对比

Options API 使用 mixins,容易命名冲突:

// mixin
const counterMixin = {
  data() {
    return { count: 0 }
  },
  methods: {
    increment() { this.count++ }
  }
}

export default {
  mixins: [counterMixin]
}

Composition API 使用组合函数,更清晰:

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

export function useCounter() {
  const count = ref(0)
  const increment = () => count.value++
  return { count, increment }
}

// 组件中使用
import { useCounter } from './useCounter'

const { count, increment } = useCounter()

关键点

  • ref 用于基本类型,访问需要 .valuereactive 用于对象类型,直接访问属性
  • toRef/toRefs 解决 reactive 对象解构丢失响应式的问题
  • Options API 按选项分类(data/methods/computed),Composition API 按功能逻辑组织
  • Composition API 通过组合函数实现逻辑复用,比 mixins 更清晰,无命名冲突
  • <script setup> 是 Composition API 的语法糖,更简洁