Vue 3 Composition API深度探索与最佳实践

引言

Vue 3的Composition API是框架演进中的重要里程碑,它提供了更灵活的逻辑组织和复用方式。本文将深入探讨Composition API的设计理念、核心特性以及在实际项目中的最佳实践。

Composition API vs Options API

逻辑关注点分离

Options API按照选项类型组织代码,导致相同逻辑分散在不同选项中:

// Options API方式
export default {
  data() {
    return {
      posts: [],
      currentPage: 1
    }
  },
  computed: {
    paginatedPosts() {
      // 分页逻辑
    }
  },
  methods: {
    fetchPosts() {
      // 获取数据逻辑
    }
  },
  mounted() {
    this.fetchPosts()
  }
}

Composition API则按照逻辑功能组织代码:

// Composition API方式
import { ref, computed, onMounted } from 'vue'

export default {
  setup() {
    const posts = ref([])
    const currentPage = ref(1)
    
    const paginatedPosts = computed(() => {
      // 分页逻辑
      return posts.value.slice(0, 10)
    })
    
    const fetchPosts = async () => {
      // 获取数据逻辑
    }
    
    onMounted(fetchPosts)
    
    return {
      posts,
      currentPage,
      paginatedPosts,
      fetchPosts
    }
  }
}

更好的TypeScript支持

Composition API天然支持类型推断,提供了更好的TypeScript开发体验:

interface User {
  id: number
  name: string
  email: string
}

export default defineComponent({
  setup() {
    const user = ref<User | null>(null)
    const loading = ref<boolean>(false)
    
    const fetchUser = async (id: number): Promise<void> => {
      // 类型安全的API调用
    }
    
    return {
      user,
      loading,
      fetchUser
    }
  }
})

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

Composition API最强大的特性是能够创建自定义组合函数,实现跨组件逻辑复用:

// usePagination.js
import { ref, computed } from 'vue'

export function usePagination(items, itemsPerPage = 10) {
  const currentPage = ref(1)
  
  const totalPages = computed(() => 
    Math.ceil(items.value.length / itemsPerPage)
  )
  
  const paginatedItems = computed(() => {
    const start = (currentPage.value - 1) * itemsPerPage
    const end = start + itemsPerPage
    return items.value.slice(start, end)
  })
  
  function nextPage() {
    if (currentPage.value < totalPages.value) {
      currentPage.value++
    }
  }
  
  function prevPage() {
    if (currentPage.value > 1) {
      currentPage.value--
    }
  }
  
  return {
    currentPage,
    totalPages,
    paginatedItems,
    nextPage,
    prevPage
  }
}

在组件中使用:

import { usePagination } from '@/composables/usePagination'

export default {
  setup() {
    const items = ref([...]) // 数据源
    
    const {
      currentPage,
      totalPages,
      paginatedItems,
      nextPage,
      prevPage
    } = usePagination(items, 20)
    
    return {
      currentPage,
      totalPages,
      paginatedItems,
      nextPage,
      prevPage
    }
  }
}

响应式进阶技巧

响应式工具函数

Vue 3提供了一系列响应式工具函数:

import { 
  isRef, 
  unref, 
  toRef, 
  toRefs, 
  customRef 
} from 'vue'

// 自定义ref实现防抖
function useDebouncedRef(value, delay = 200) {
  let timeout
  return customRef((track, trigger) => {
    return {
      get() {
        track()
        return value
      },
      set(newValue) {
        clearTimeout(timeout)
        timeout = setTimeout(() => {
          value = newValue
          trigger()
        }, delay)
      }
    }
  })
}

Effect Scope管理副作用

Vue 3.2引入了effectScopeAPI,用于集中管理副作用:

import { effectScope, onScopeDispose } from 'vue'

export function useMouse() {
  const x = ref(0)
  const y = ref(0)
  
  function update(e) {
    x.value = e.pageX
    y.value = e.pageY
  }
  
  const scope = effectScope()
  
  scope.run(() => {
    onMounted(() => window.addEventListener('mousemove', update))
    onUnmounted(() => window.removeEventListener('mousemove', update))
  })
  
  // 停止所有副作用
  const stop = () => scope.stop()
  
  onScopeDispose(stop)
  
  return { x, y, stop }
}

性能优化与最佳实践

1. 合理使用ref和reactive

  • 使用ref处理基本类型和对象引用替换
  • 使用reactive处理不需要引用替换的对象

2. 减少不必要的响应式开销

// 不佳:创建了不必要的响应式对象
const state = reactive({
  largeData: bigData // bigData很大且不需要响应式
})

// 更佳:分离响应式和非响应式数据
const state = reactive({
  // 只有需要响应式的数据才放在这里
})
const nonReactiveData = ref(bigData) // 或直接使用原始数据

3. 使用provide/inject进行跨组件状态共享

// 父组件
import { provide, reactive } from 'vue'

export default {
  setup() {
    const globalState = reactive({
      user: null,
      theme: 'light'
    })
    
    provide('globalState', globalState)
    
    return { globalState }
  }
}

// 子组件
import { inject } from 'vue'

export default {
  setup() {
    const globalState = inject('globalState')
    
    return { globalState }
  }
}

结语

Composition API为Vue应用开发带来了全新的编程模式和可能性。通过合理利用组合函数、响应式工具和性能优化技巧,我们可以构建出更健壮、可维护和高性能的Vue应用。随着Vue生态的不断发展,Composition API将成为Vue开发的标准方式,值得每位Vue开发者深入学习和掌握。

更多推荐