跳过导航,直达内容
2026-04-28 技术团队 10 分钟

Vue 3 Composition API 高级模式与最佳实践

Vue.js前端最佳实践
Vue 3 Composition API 高级模式与最佳实践

Vue 3 发布已有数年,Composition API 已经成为 Vue 生态的标准开发范式。然而在代码评审中,我们仍然频繁看到 Options API 思维下的"Composition API 写法"——将选项式代码机械地搬进 setup 函数,未能发挥 Composition API 的真正威力。

组合优于继承:Composable 设计原则

Composition API 的核心思想是"按功能组织代码,而非按选项分散代码"。一个好的 Composable 应遵循"单一职责"——每个 Composable 只负责一个明确的功能领域:

  • useUserAuth:认证状态、登录/登出、Token 管理
  • useProductList:列表数据、分页、筛选、排序
  • useFormValidation:表单校验规则、错误状态、提交处理
  • useMediaQuery:响应式断点检测

命名规范:必须使用 use 前缀,这是 Vue 社区的约定,也是 ESLint 规则可以自动检查的。返回结构建议浅层对象而非嵌套对象,减少使用方的解构心智负担。

状态管理:什么该进 Pinia?

并非所有状态都需要中心化 Store。我们遵循简单的决策树:组件内部状态 → ref/reactive;父子传递 → props/emitsprovide/inject;跨组件共享且有复杂逻辑 → Pinia Store。

一个常见反模式是"过早抽象"——在所有状态上套一层 Pinia。这样不仅增加代码量,还使状态流变得难以追踪。正确的做法是"延迟决策":先写组件内的 ref,当确实需要跨组件共享时,再重构为 Store。

异步数据的三态模式

// composables/useAsyncData.ts
export function useAsyncData<T>(fetcher: () => Promise<T>) {
  const data = shallowRef<T | null>(null)
  const isLoading = ref(false)
  const error = shallowRef<Error | null>(null)

  async function execute() {
    isLoading.value = true
    error.value = null
    try {
      data.value = await fetcher()
    } catch (e) {
      error.value = e as Error
    } finally {
      isLoading.value = false
    }
  }

  return { data, isLoading, error, execute }
}

这种模式让模板可以优雅地处理三种状态,避免"闪现错误"和"无限 Loading"。对于更复杂的场景(缓存、去重、后台刷新),推荐使用 TanStack Query(Vue 版)或 VueUse 的 useAsyncState