写 Vue 我建议非必要别用 watch

写 Vue 我建议非必要别用 watch

💡 原文中文,约3500字,阅读约需9分钟。
📝

内容提要

文章主张Vue中非必要别用watch。以列表页为例,原用三个watch处理路由、关键词和分页变化,逻辑相互依赖、耦合严重,且watch语义不明确,只说明依赖值变化,未解释原因,还容易让人不写注释。建议仅在触发点超过两个、所有场景共用同一逻辑且与其他watch无耦合时使用。优化后只保留路由watch,搜索和分页改用事件触发,逻辑更清爽易读。

🔎

延伸解读

watch 的语义模糊性

文章指出 watch 只声明了对某个值的依赖,却没有解释依赖的原因。当值变化时,触发逻辑看似理所当然,但变化的原因可能多种多样,导致代码意图不明确。开发者容易因此忽略注释,时间一长连自己都难以理解。这种语义上的模糊是 watch 被滥用的重要原因。

多 watch 耦合的典型表现

在列表页示例中,三个 watch 分别监听路由、关键词和分页,但关键词变化时需要重置分页,分页变化又触发请求,形成了类似任务委托的链式调用。这种相互依赖的逻辑使得代码耦合严重,难以维护和调试,也增加了理解成本。

事件驱动替代 watch 的实践

优化后,仅保留路由 watch,搜索和分页改为事件触发。搜索时直接重置分页并请求,分页组件通过 @update:page 触发请求。这样消除了 watch 间的耦合和条件判断,逻辑更线性、易读。文章建议,当触发点超过两个、所有场景共用同一逻辑且无耦合时才考虑 watch。

❓

Q&A

为什么在 Vue 中建议非必要别用 watch?

watch 的语义不明确,它只说明依赖的值发生了变化,但没有解释变化的原因,容易导致逻辑耦合和缺乏注释。多个 watch 之间可能相互依赖,形成类似任务委托的复杂逻辑,降低代码可读性和可维护性。

在什么情况下才应该考虑使用 watch?

最好满足以下条件:变动触发点大于 2 个;所有场景都适用同一个处理逻辑;与其他 watch 没有耦合。如果只有一个触发机会,直接在该时机调用即可,无需 watch。

文章中的列表页案例原本用了几个 watch?它们是如何相互依赖的?

原本用了 3 个 watch,分别监听 route.params.type、pagination.page 和 keyword.value。它们之间存在依赖:keyword 改变时需要重置 pagination,然后触发请求;route.params.type 改变时需要重置 pagination 和 keyword。逻辑相互耦合,甚至写成类似任务委托的效果。

优化后如何替代 watch 处理搜索和分页?

优化后只保留 route.params.type 的 watch,搜索和分页改用事件触发。搜索通过 handleSearch 事件直接重置分页并请求,分页通过 Pagination 组件的 @update:page 事件触发 fetchList,无需额外写 @change。

watchEffect 能解决 watch 的问题吗?

watchEffect 仍然存在类似问题,需要在内部额外添加 if else 处理重置逻辑。不过将逻辑集中在一个 watchEffect 中,可能比分散在多个 watch 里更好,但并未从根本上解决语义不明确和耦合的问题。

为什么说 watch 容易让人不写注释?

watch 给人一种“值变了就运行下面的逻辑是理所当然”的错觉,导致开发者容易忽略注释。但值变化的原因可能很多,缺乏注释会使后续维护者(包括自己)难以理解逻辑,尤其是两个月后回顾代码时。

🏷️

标签

➡️

继续阅读