Skip to content

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应用。

参考资料

  1. Vue3官方文档
  2. Composition API RFC
  3. Vue Test Utils文档
  4. TypeScript文档

幸运的人用童年治愈一生,不幸的人用一生治愈童年 —— 强爸