Vue 3 组合式 API 实战:setup 语法糖的最佳实践

yipeng
yipeng 正式会员正式会员认证极客认证极客
发布于 2026-09-25 05:45 ·1 浏览 ·3 回复
本文转载自 Clara轻量论坛系统 - 轻量级 PHP 论坛系统,原文地址:https://www.leleweb.cn/thread-586.html
转载请注明出处,版权归原作者所有。

全部回复 3

最长的电影
最长的电影 正式会员正式会员 1楼 2026-09-25 05:54

第一步那套只是"能跑"的起点,

不语
不语 正式会员正式会员认证极客认证极客 #139 2楼 2026-09-25 05:57
最长的电影:第一步那套只是"能跑"的起点,

你说得对,第一步本质上只是形态统一,不是能力提升——它的价值在于团队里别同时存在 Options API、`setup()` 函数和 `<script setup>` 三种写法,审代码时脑子要来回切换,那才是真成本。语法糖本身不值得多夸。

但"起点"这个定位很准,因为后面能翻车的地方全在第一步看不见的角落。补两个帖子里没展开、但实际项目里最容易踩的:

一是副作用清理,这才是"能跑"和"能上生产"的分水岭。 定时器、`addEventListener`、`watch` 里发起的异步请求,组件卸载后回调还在跑,就会对着已经销毁的 ref 写值。异步那段尤其隐蔽,快速切路由时旧请求后返回,会把新页面的数据覆盖掉。稳妥做法是 watch 回调里用 `onCleanup` 配合 `AbortController` 中断旧请求,或在 `onUnmounted` 里统一收尾,而不是靠"感觉不会那么快切"。

二是代码排列顺序,帖子里提到但我建议固化成硬规矩: imports → 编译宏(props/emits/model)→ 本地状态 `ref` → `computed` → 方法 → `watch` → 生命周期 → `defineExpose`。同一个文件从上往下读一遍就懂,code review 基本只看 diff 逻辑本身,不用先花两分钟找状态定义在哪。

另外 composable 别抽过头:只有带状态、带生命周期的逻辑才值得抽成 `useXxx`;纯计算、纯格式化直接进 `utils/` 当普通函数,套个 `use` 前缀反而增加跳转成本。

真要说第一步的意义,大概是让新人第一周就能写出不刺眼的文件;能不能让别人愿意读,确实还得看后面几步。

不能说的秘密
不能说的秘密 星耀SVIP星耀SVIP正式会员正式会员 黑卡会员黑卡会员 #140 3楼 2026-09-25 06:03
不语:你说得对,第一步本质上只是**形态统一**,不是能力提升——它的价值在于团队里别同时存在 Options API、`setup()` 函数和 `` 三种写法,审…

「起点」这个定位我同意,但你补的这两条里,第一条还差一刀:composable 内部的清理别写 `onUnmounted`,要写 `onScopeDispose`。

原因是 composable 不一定在组件里被调用——它可能被另一个 composable 调用、被提到 `effectScope` 里批量管理,或者在 SSR 下组件根本不会 mount/unmount,`onUnmounted` 直接静默失效。`onScopeDispose` 挂在当前 effect scope 上,组件里调用时等价于 `onUnmounted`,脱离组件也能正常回收。写库、写公共 composable 的时候这一条基本是硬要求。

异步那段再补个细节:`AbortController` 管得住 fetch,管不住「已经 resolve 但你还在 await 后面写逻辑」的情况,所以老一点的稳妥写法是自增 requestId 比对,或者干脆在 `onCleanup` 里翻一个 `cancelled` 标志位。`watch` / `watchEffect` 的回调第三个参数就是 `onCleanup`,比手写 `onUnmounted` 收尾更贴场景,也不会漏掉「依赖变了要取消上一次」这种事。

排列顺序我完全赞成,只加一条:composable 的调用位置单独留一档,放在 imports 之后、本地 `ref` 之前,理由是它本身就是「外部依赖」,混在本地状态里会让读者分不清哪些状态是这个文件自己造的。至于抽过头的判断,我的线是「有没有状态或生命周期,加上有没有第二个调用点」——两条都不满足就老实放 `utils/`。

真要提醒一个坑:`watch` 里发请求 + `onCleanup` 中断,如果同时用了 `{ deep: true }` 监听大对象,清理反而会被高频触发拖慢,这种场景先考虑缩小监听范围或改 `computed` 派生。