Vue3 引入了 Composition API,这是一个全新的组件编写方式,它提供了更好的逻辑复用、类型推断和代码组织能力。本文将带你从零开始学习 Composition API 的核心概念和用法。
什么是 Composition API?
Composition API 是 Vue3 提供的一套基于函数的 API,它允许我们通过组合函数的方式来组织组件逻辑,而不是通过选项(data、methods、computed 等)来组织。
为什么需要 Composition API?
在 Vue2 中,当组件变得复杂时,相关的逻辑会被分散在不同的选项中:
// Vue2 Options API 的问题
export default {
data() {
return {
count: 0,
message: 'Hello'
}
},
methods: {
increment() {
this.count++
},
updateMessage() {
this.message = 'Updated'
}
},
computed: {
doubleCount() {
return this.count * 2
}
},
// 相关的逻辑分散在不同地方
}
使用 Composition API,我们可以将相关的逻辑组织在一起:
// Vue3 Composition API
import { ref, computed } from 'vue'
export default {
setup() {
// 所有相关的逻辑都在这里
const count = ref(0)
const message = ref('Hello')
const increment = () => {
count.value++
}
const updateMessage = () => {
message.value = 'Updated'
}
const doubleCount = computed(() => count.value * 2)
return {
count,
message,
increment,
updateMessage,
doubleCount
}
}
}
核心 API 详解
1. setup 函数
setup 是 Composition API 的入口函数,它在组件创建之前执行,接收 props 和 context 两个参数:
export default {
props: {
title: String
},
setup(props, context) {
// props 是响应式的,但不要解构它
console.log(props.title)
// context 包含 attrs、slots、emit
const { attrs, slots, emit } = context
return {
// 返回的内容可以在模板中使用
}
}
}
2. ref 和 reactive
ref 和 reactive 是创建响应式数据的两种方式:
ref - 用于基本类型和对象引用:
import { ref } from 'vue'
const count = ref(0)
const user = ref({ name: 'John', age: 30 })
// 访问值需要使用 .value
console.log(count.value) // 0
count.value++
// 在模板中会自动解包,不需要 .value
reactive - 用于对象和数组:
import { reactive } from 'vue'
const state = reactive({
count: 0,
user: {
name: 'John',
age: 30
}
})
// 直接访问,不需要 .value
console.log(state.count) // 0
state.count++
3. computed 计算属性
computed 用于创建计算属性:
import { ref, computed } from 'vue'
const count = ref(0)
const doubleCount = computed(() => count.value * 2)
// 只读计算属性
console.log(doubleCount.value) // 0
// 可写计算属性
const fullName = computed({
get() {
return `${firstName.value} ${lastName.value}`
},
set(newValue) {
[firstName.value, lastName.value] = newValue.split(' ')
}
})
4. watch 和 watchEffect
watch - 监听特定数据源的变化:
import { ref, watch } from 'vue'
const count = ref(0)
const message = ref('')
// 监听单个源
watch(count, (newVal, oldVal) => {
console.log(`count changed from ${oldVal} to ${newVal}`)
})
// 监听多个源
watch([count, message], ([newCount, newMessage], [oldCount, oldMessage]) => {
console.log('count or message changed')
})
// 深度监听对象
const state = reactive({ user: { name: 'John' } })
watch(() => state.user, (newVal) => {
console.log('user changed')
}, { deep: true })
watchEffect - 自动追踪依赖并执行:
import { ref, watchEffect } from 'vue'
const count = ref(0)
watchEffect(() => {
// 自动追踪 count,当 count 变化时重新执行
console.log(`count is ${count.value}`)
})
5. 生命周期钩子
Composition API 提供了对应的生命周期函数:
import { onMounted, onUpdated, onUnmounted } from 'vue'
export default {
setup() {
onMounted(() => {
console.log('组件已挂载')
})
onUpdated(() => {
console.log('组件已更新')
})
onUnmounted(() => {
console.log('组件已卸载')
})
}
}
实际应用示例
示例 1: 计数器组件
<template>
<div>
<p>Count: {{ count }}</p>
<p>Double: {{ doubleCount }}</p>
<button @click="increment">+1</button>
<button @click="decrement">-1</button>
</div>
</template>
<script>
import { ref, computed } from 'vue'
export default {
setup() {
const count = ref(0)
const increment = () => {
count.value++
}
const decrement = () => {
count.value--
}
const doubleCount = computed(() => count.value * 2)
return {
count,
increment,
decrement,
doubleCount
}
}
}
</script>
示例 2: 数据获取
import { ref, onMounted } from 'vue'
export function useFetch(url) {
const data = ref(null)
const loading = ref(false)
const error = ref(null)
const fetchData = async () => {
loading.value = true
error.value = null
try {
const response = await fetch(url)
data.value = await response.json()
} catch (e) {
error.value = e
} finally {
loading.value = false
}
}
onMounted(() => {
fetchData()
})
return {
data,
loading,
error,
refetch: fetchData
}
}
最佳实践
- 使用
<script setup>语法糖(Vue3.2+):
<script setup>
import { ref, computed } from 'vue'
const count = ref(0)
const doubleCount = computed(() => count.value * 2)
</script>
- 提取可复用的逻辑到 composables:
// composables/useCounter.js
import { ref } from 'vue'
export function useCounter(initialValue = 0) {
const count = ref(initialValue)
const increment = () => count.value++
const decrement = () => count.value--
const reset = () => count.value = initialValue
return {
count,
increment,
decrement,
reset
}
}
- 合理使用 ref 和 reactive:
- 基本类型使用
ref - 对象和数组可以使用
reactive,但ref更通用
- 基本类型使用
总结
Composition API 为 Vue3 带来了更强大的逻辑组织和复用能力。通过合理使用 setup、ref、reactive、computed、watch 等 API,我们可以编写出更清晰、更易维护的组件代码。
虽然学习曲线可能比 Options API 陡峭一些,但一旦掌握,你会发现它带来的好处是值得的。建议在实际项目中逐步迁移,先从新组件开始使用 Composition API。
希望这篇文章能帮助你更好地理解和使用 Vue3 Composition API。如果你有任何问题或建议,欢迎在评论区讨论!