把 300 行的 Vue3 组件拆成 composable:一次真实重构
接手了一个历史页面,单个 SFC 接近 300 行,template 里混着五段逻辑:问卷加载、倒计时、答案暂存、草稿恢复、埋点上报。改任何一个地方都要在几百行里上下跳,review 也难受。这周下决心用 Vue3 的组合式 API 拆了一遍,记录下思路。
拆分原则很简单:按「职责」而不是按「代码类型」分组。原来的写法是 data 里二十个字段、methods 里十几个函数,彼此耦合;重构后每个职责一个 composable,各自持有自己的状态和方法。
以倒计时为例,抽出来的 useCountdown 长这样:
import { ref, onUnmounted } from 'vue'
export function useCountdown(seconds: number) {
const left = ref(seconds)
const timer = setInterval(() => {
left.value -= 1
if (left.value <= 0) clearInterval(timer)
}, 1000)
// 组件卸载时清理,避免定时器泄漏
onUnmounted(() => clearInterval(timer))
return { left }
}
关键点在于 onUnmounted 可以写在 composable 里,只要这个函数在 setup 中被调用,生命周期就会正确挂到宿主组件上。这一点比 Vue2 的 mixin 干净太多——mixin 里的变量来源不明,composable 的来源一目了然。
草稿恢复那段抽成了 useDraft,内部用 localStorage 做 key-value 存取,对外只暴露 save 和 restore 两个方法。埋点抽成 useTracker 后,页面里只剩一个统一的 report 函数入口,运营要加事件名也不用动业务代码。
拆完之后的 SFC 只剩 80 行左右,template 负责展示,setup 里是四行解构调用。后续有个同事要在另一个活动页复用倒计时,直接 import 就能用,这大概就是这次重构最直接的收益。
几点体会:第一,不要为了拆而拆,两三行逻辑不值得一个文件;第二,composable 的返回值用 ref 而不是 reactive,避免解构后失去响应性,真要解构 reactive 就配 toRefs;第三,命名统一用 useXxx,参数尽量支持传入回调而非把回调写死,复用时会灵活很多。
- 点赞
- 收藏
- 关注作者
评论(0)