Vue3 Composition API最佳实践指南
引言
Vue3的Composition API为我们提供了更好的代码组织方式和逻辑复用能力。本文将介绍Composition API的最佳实践和常见模式。
基础概念
响应式系统
typescript
import { ref, reactive, computed } from 'vue'
// ref用于基本类型
const count = ref(0)
// reactive用于对象
const state = reactive({
user: {
name: '张三',
age: 25
}
})
// computed计算属性
const doubleCount = computed(() => count.value * 2)
生命周期钩子
typescript
import { onMounted, onUnmounted, onUpdated } from 'vue'
export default {
setup() {
onMounted(() => {
console.log('组件已挂载')
})
onUnmounted(() => {
console.log('组件已卸载')
})
onUpdated(() => {
console.log('组件已更新')
})
}
}
逻辑复用
可复用的组合式函数
typescript
// useUser.ts
import { ref, onMounted } from 'vue'
import type { User } from '@/types'
export function useUser(userId: string) {
const user = ref<User | null>(null)
const loading = ref(true)
const error = ref<Error | null>(null)
const fetchUser = async () => {
try {
loading.value = true
const response = await fetch(`/api/users/${userId}`)
user.value = await response.json()
} catch (e) {
error.value = e as Error
} finally {
loading.value = false
}
}
onMounted(fetchUser)
return {
user,
loading,
error,
fetchUser
}
}
使用组合式函数
vue
<template>
<div v-if="loading">加载中...</div>
<div v-else-if="error">{{ error.message }}</div>
<div v-else>
<h2>{{ user.name }}</h2>
<p>{{ user.email }}</p>
</div>
</template>
<script setup lang="ts">
import { useUser } from '@/composables/useUser'
const { user, loading, error } = useUser('123')
</script>
状态管理
Pinia集成
typescript
// stores/user.ts
import { defineStore } from 'pinia'
export const useUserStore = defineStore('user', {
state: () => ({
user: null,
token: null
}),
getters: {
isLoggedIn: (state) => !!state.token
},
actions: {
async login(username: string, password: string) {
// 登录逻辑
},
logout() {
this.user = null
this.token = null
}
}
})
性能优化
组件缓存
vue
<template>
<KeepAlive>
<component :is="currentComponent" />
</KeepAlive>
</template>
<script setup lang="ts">
import { shallowRef } from 'vue'
const currentComponent = shallowRef('HomeView')
</script>
异步组件
typescript
import { defineAsyncComponent } from 'vue'
const AsyncComponent = defineAsyncComponent({
loader: () => import('./components/HeavyComponent.vue'),
loadingComponent: LoadingSpinner,
delay: 200,
timeout: 3000
})
TypeScript集成
类型定义
typescript
interface Props {
title: string
items: string[]
onSelect?: (item: string) => void
}
const props = withDefaults(defineProps<Props>(), {
items: () => []
})
const emit = defineEmits<{
(e: 'select', item: string): void
(e: 'update', value: string): void
}>()
测试最佳实践
组件测试
typescript
import { mount } from '@vue/test-utils'
import { describe, it, expect } from 'vitest'
import UserProfile from './UserProfile.vue'
describe('UserProfile', () => {
it('renders user information correctly', () => {
const wrapper = mount(UserProfile, {
props: {
user: {
name: '张三',
email: '[email protected]'
}
}
})
expect(wrapper.text()).toContain('张三')
expect(wrapper.text()).toContain('[email protected]')
})
})
项目结构
src/
├── assets/
├── components/
│ ├── common/
│ └── features/
├── composables/
│ ├── useUser.ts
│ └── useAuth.ts
├── stores/
│ ├── user.ts
│ └── app.ts
├── views/
└── App.vue
错误处理
typescript
import { onErrorCaptured } from 'vue'
export default {
setup() {
onErrorCaptured((err, instance, info) => {
console.error('组件错误:', err)
// 上报错误到监控系统
reportError(err, info)
return false // 阻止错误继续传播
})
}
}
总结
Vue3 Composition API提供了更灵活和可维护的代码组织方式。通过合理使用这些特性,我们可以构建出更好的Vue应用。
参考资料
- Vue3官方文档
- Composition API RFC
- Vue Test Utils文档
- TypeScript文档