很多文章在讲 Vue Setup 引入了新语法,以及新语法怎么用。

本文想聊聊 Vue 为什么 引入 Setup。

核心观点:Composition API 的真正价值,不仅仅是逻辑复用,更是一场代码组织方式的进化

组件里的“寻宝游戏”

先回想一个熟悉的场景。

当你需要修改一个“用户信息模块”的功能时,在 Options API 的组件里,你需要经历什么?

  1. data 里找 user 状态定义。
  2. methods 里找 fetchUser 方法实现。
  3. mounted 里找初始化调用。
  4. watch 里找 userId 变化后的逻辑。

对于稍大一些的组件,页面反复滚动,思维上下横跳是开发常态。

//  Options API 实现:同一功能被强制拆散

export default {
  data() {
    return {
      //  用户模块
      user: null,
      loading: false,
      //  搜索模块
      keyword: '',
      results: [],
    }
  },

  methods: {
    //  用户模块
    async fetchUser() { /* ... */ },
    //  搜索模块
    async search() { /* ... */ },
  },

  watch: {
    //  用户模块(字符串写法更隐式!)
    userId: 'fetchUser',
    //  搜索模块
    keyword: 'search',
  },

  mounted() {
    //  用户模块
    this.fetchUser()
  },
}

这不是你的问题,是范式的问题。

Options API 强制我们按“选项类型”组织代码(把状态放一起、把方法放一起)。但人类的大脑是按“业务逻辑”思考的(用户模块、搜索模块、表单模块)。

当组件简单时,这种分散无关痛痒。但当组件变大, “框架的分类方式”就成了“代码组织的天花板” 。我们不是在写业务,而是在填框架定义的表格。

理想结构:按“业务能力”聚合

抛开 Vue 的语法限制,我们心中理想的组件结构,应该是按“逻辑关注点(Logical Concerns)”聚合的。

同一个功能的状态、方法、副作用、生命周期,应该物理相邻

让我们将上面的 Options 功能全部打散,看看这段伪代码,这是我们在没有框架限制时,最自然的写法:

//  我们理想中的代码结构:按功能块排列

//  用户模块
状态:{ user, loading }
方法:{ fetchUser }
:{ userId -> fetchUser }
生命周期:{ mounted -> fetchUser }

//  搜索模块
状态:{ keyword, results }
方法:{ search }
:{ keyword -> search }
  • 代码都写在一起
  • 按功能块组织

在这种结构下:

  1. 内聚性:修改“用户功能”,只需关注第一个代码块,无需跳转。
  2. 可读性:新人接手,看代码块注释就知道有哪些功能模块。
  3. 可维护性:删除功能,直接删掉一个块,不会残留碎片。

Vue 引入 Setup,就是为了让我们能写出接近这种理想结构的代码。

Setup 与工具函数

Vue 的 setup 函数,就是让你写所有代码的地方。

附带提供的一套工具函数(ref, watch, onMounted 等),能让你按业务逻辑组织代码。

让我们把上面的理想伪代码,翻译成真实的 Vue Setup 写法的代码:

export default {
  setup(props) {
    //  用户模块
    const user = ref(null)          // 状态
    const loading = ref(false)      // 状态
    
    async function fetchUser() {    // 方法
      /* ... */ 
    }
    
    watch(() => props.userId, fetchUser)        // 
    onMounted(fetchUser)            // 生命周期

    //  搜索模块
    const keyword = ref('')         // 状态
    
    async function search() {       // 方法
      /* ... */ 
    }
    
    watch(keyword, search)          // 

    return { user, loading, keyword, search }
  }
}

我们想要的:

统统达成。

额外收益: 当代码按业务逻辑聚合后,你会发现: "提取复用"变成了一个自然的水到渠成的动作

今天写在 setup 里的"用户模块"代码块, 明天只需要包一层函数、定义好输入输出, 就能变成一个可复用的 useUser() 组合函数。

具体怎么提取、有哪些最佳实践,我们下篇实战文章细聊

为什么 mixin 不行?

读到这儿,可能有 Options API 的老用户会问:

这是一个非常好的问题。确实,Mixin 也能把相关代码组织在一起。

但从 实际使用 的维度看,Mixin 存在致命缺陷。

// UserMixin.js
export default {
  data() { return { user: null } },
  methods: { fetchUser() {} }
}

// Component.vue
export default {
  mixins: [UserMixin],
  // 问题:this.user 从哪来?IDE 无法提示,阅读时需要跳转文件
  mounted() {
    this.fetchUser() // 这个方法是哪来的?需要去 Mixin 里找
  }
}

Mixin 的三个使用缺陷:

  1. 来源不透明:在组件里看不到 user 的定义,除非把组件用到的所有 mixin 都看一遍。
  2. 命名冲突:如果两个 mixin 都定义了 user,后引入的会覆盖先引入的,且没有任何警告。
  3. 数据流向模糊:组件依赖了哪些 mixin 属性?无法肉眼识别,只能靠运行时验证。

总结:为什么强烈建议用 Setup?

回到最初的问题:为什么写 Vue 强烈建议用 Setup?

维度Options APISetup
代码组织按"选项类型"分散 按"业务逻辑"聚合
可读性需要脑内拼合逻辑 同一功能物理相邻
可维护性修改需跨多处跳转 就近修改,无遗漏
可复用性Mixin 隐式+冲突 函数显式+类型友好
可演进性提取复用成本高 聚合后自然可提取

核心结论

Options API 并没有错,它在小型组件、初学者场景下依然清晰。 但当你的组件越来越复杂,强制按类型组织代码就会成为一种技术债务

Setup 不是为了让代码变复杂, 而是为了当你在面对一个 1000 行的组件时,不至于无从下手。

下一步:别把 Setup 写成 Options

理解了 Setup 的设计动机,不代表能写好 Composition API。

我观察到一个普遍现象: 很多开发者虽然用了 Setup,但只是把 Options 的代码搬运进了 setup 函数:

  • dataref
  • methodsfunction
  • mountedonMounted

结果写出了 "换皮版"的组合式代码

  • 既没享受到"按逻辑聚合"的组织红利
  • 又失去了 Options"结构清晰"的入门友好

有了"自由",不等于会"用好"。

在下一篇实战文章中,我将从一个真实的详情页案例出发,带你:

3 步升级,真正吃透 Composition API

步骤升级内容解决什么问题
升级 1在 setup 内按功能模块组织代码告别"大仓库",让同一功能的代码物理相邻
升级 2拆分 setup,抽成 useXxx 组合函数逻辑复用变得自然,输入输出显式可控
升级 3从生命周期驱动转向数据驱动watch 替代 onMounted,让代码更声明式

立即阅读下篇:别再写换皮 Options 了!Vue3 Setup 的真正用法是这3步升级

本站提供的所有下载资源均来自互联网,仅提供学习交流使用,版权归原作者所有。如需商业使用,请联系原作者获得授权。 如您发现有涉嫌侵权的内容,请联系我们 邮箱:alixiixcom@163.com