前言
哈喽大家好,我是 嘟老板。最近接了个成本千万级的业务系统运维工作,前端是用 Vue3
写的。看了代码之后,我大为震惊,让我不得不重新思考下使用 Vue3
的正确姿势。
本文设计
Vue3
computed
watch
以及ref
的相关说明及反面案例
这是 千万级项目反思 系列的第 1 篇,其他文章见:
正文
业务场景:
某业务单据管理模块,单据详情页面允许同时打开多个(单据 id
不同的情况下),需要根据不同的操作类型(新增、查看、编辑等)对页面元素进行控制,如:查看操作不允许任何编辑操作,新增/编辑操作则允许编辑。操作类型会在从上级页面跳转时添加到 URL
参数上,即使用 vue-router
push
函数参数的 query
属性实现。
项目代码
清楚了业务,我们来看看原项目的小伙伴是如何实现的:
const route = useRoute()
const isView = ref(route.query.opType === 'view')
watch(
() => route,
(newVal) => {
if (newValue.query.opType === 'view') isView.value = true
},
{
deep: true,
immediate: true
}
)
以上是精简过的代码,核心思路是通过 isView
来控制页面元素的编辑状态,isView
的值由操作类型 route.query.opType
确定,若其等于 view
,则为 true
,否则为 false
。
分析
上面代码看似是实现了业务功能,监听路由 route
变更,以更新 isView
的值,达到控制页面元素编辑状态的目的。
那么哪里让我陷入沉思了呢?主要有以下两点:
isView
的值仅仅由路径参数opType
决定,是否有必要手动赋值?- 仅为了获取路由参数
opType
的值,是否有必要始终监听route
对象?
针对以上两个问题,我的答案都是否。因为 isView
的值来源单一,仅仅是通过 opType
来决定,没有其他任何需要赋值的逻辑;而且对于 route
对象,很可能 queyr.opType
不会变更,而变更其他属性,如 name
,path
等,或 query
的其他属性值,这种情况不需要为 isView
重新赋值,如果可以用缓存的值那就完美了。
鉴于以上思路,我认为针对此业务场景,使用 计算属性 computed
更为适合。
computed 和 watch 的区别
我们来简单回顾一下 computed
和 watch
的主要区别,两者都可以监听响应式依赖的变化。
computed
接收一个getter
函数作为参数,返回一个计算属性ref
,有缓存,仅响应式依赖变更时才重新计算,否则使用缓存的值。watcher
在响应式依赖发生变化时执行副作用函数,无缓存,返回值是一个停止watch
的函数。
可见,computed
可用于定义 ref
变量,且可缓存,无需每次 route
对象变更时都重新计算。
ref 与 computed 定义变量的区别
由于 ref
和 computed
都可创建响应式数据,因此也拉来一起比一比😄
ref
比较直接,就是用来创建响应式数据的API
。computed
返回的计算属性也是响应式数据,不同之处在于,computed
不建议手动赋值,应始终保持其派生状态。即使可以通过getter/setter
的定义方式实现该特性。
优化后代码
通过以上分析,可以发现,computed
不仅可以监听 route.query.opType
的变更,还可以创建响应式数据,且有缓存,顺便小小的提升了一波性能。
const route = useRoute()
const isView = computed(() => route.query.opType === 'view')
搞定,不仅同样实现了业务功能,还减少了代码量,更提升了可读性和维护性,perfect!!!
结语
好啦,本文内容就到这里。实践出真知,只有真正动手实践,真正参与其中才能更深刻的体会到技术的魅力,才能总结出更合理的开发方式,爱动手的小伙伴们赶快行动起来吧😁。
若本文内容有错误或遗漏的地方,欢迎评论指出。感谢阅读,愿你我共同进步,谢谢!!!