刚开始写 Vue 3 时,很容易把 Composition API 理解成一种更自由的写法:所有变量、方法、监听器都可以放在同一个 setup 里。但项目稍微变大以后,这种自由会变成新的混乱。一个页面可能同时有表单状态、接口加载、弹窗控制、列表筛选、权限判断和埋点逻辑,如果没有组织方式,代码会比 Options API 更难读。

一、先按业务流程分组

我更习惯先按页面里的业务流程分组,而不是按 API 类型分组。比如列表页可以分成筛选条件、列表数据、分页、批量操作和弹窗编辑。每组内部再放自己的 refcomputed、方法和监听器。这样读代码时可以顺着用户操作理解,而不是在一堆变量和方法之间来回跳。

如果某组逻辑已经足够独立,就可以抽成 useXxx。但抽离的标准不是“代码行数多”,而是这段逻辑有没有稳定的输入输出,能不能脱离当前组件被理解。

组合式 API 的价值在于把相关逻辑放近,而不是把所有逻辑放进同一个函数。

二、副作用要有明确位置

页面里最容易失控的是副作用:请求接口、写本地缓存、监听路由、触发提示、上报错误。它们应该放在靠近触发条件的位置,并且命名清楚。比如初始化加载可以写成 loadInitialData,筛选变化后的加载可以写成 reloadByFilters,不要都叫 getList

对于 watch,我会尽量避免写成“什么都监听一下”。监听器应该表达一个明确事实:某个来源变化后,需要同步另一个状态或触发一次受控动作。否则后续排查循环请求、重复弹窗和状态覆盖时会很痛苦。

三、复用逻辑要保留业务语义

抽 composable 时,不要为了通用而过度抽象。业务项目里很多复用逻辑不是通用工具函数,而是带语义的流程,比如“学生选择器”“兑换弹窗”“评分列表刷新”。这些逻辑保留业务命名反而更容易维护。

  • 组件内先按业务流程分组,确认结构稳定后再抽离。
  • 抽离后的函数要有清楚的参数、返回值和副作用说明。
  • 不要把所有请求都塞进一个巨大 composable,调用方会失去上下文。
  • 不要为了减少文件数量牺牲阅读顺序。

写 Vue 3 最重要的不是会用多少 API,而是让下一位读代码的人能快速知道:这个状态从哪里来、在哪里变化、会影响哪些界面。