Vue 2 计算属性与侦听器:什么时候用哪个
Vue 2 计算属性与侦听器:什么时候用哪个
刚上手 Vue 时最容易纠结的问题之一:数据变了要做点事,到底写 computed 还是 watch?官方文档说得很简洁,但实际写起来还是会混。整理一下自己的理解。
一句话分工
- computed:从已有数据派生出一个新值,模板里直接用
- watch:数据变化时执行一段副作用(发请求、操作 DOM、写 localStorage……)
判断标准很简单:你需要的是一个"值"还是一次"动作"?
computed:派生值,自带缓存
new Vue({
data() {
return {
firstName: 'Dong',
lastName: 'Xu',
}
},
computed: {
fullName() {
console.log('重新计算了')
return this.firstName + ' ' + this.lastName
},
},
})
模板里多次引用 fullName,只要依赖没变,计算函数只跑一次——这是 computed 和 methods 的本质区别。methods 每次渲染都会重新执行,computed 按依赖缓存。
用 methods 实现同样的效果,功能上没问题,但列表渲染几百个节点、每个节点调三四个方法时,性能差距就出来了。
computed 的 setter
计算属性默认只读,但也可以写 setter,做双向派生很方便:
computed: {
fullName: {
get() {
return this.firstName + ' ' + this.lastName
},
set(val) {
const parts = val.split(' ')
this.firstName = parts[0]
this.lastName = parts[1] || ''
},
},
}
v-model="fullName" 就能直接用了。
watch:变化时执行副作用
watch: {
keyword(newVal, oldVal) {
this.page = 1
this.fetchList() // 搜索词变化,重置页码并重新请求
},
}
两个实用选项:
immediate: true:初始化时立即执行一次,省掉 created 里手动调一遍deep: true:深度监听对象内部变化。注意 deep 监听大对象有性能成本,能监听具体路径就写'form.name'这种点路径
watch: {
keyword: {
handler(val) {
this.fetchList()
},
immediate: true,
},
}
常见误用
1. 用 watch 做派生值
// 反例:watch 同步另一个 data
data() {
return { firstName: '', lastName: '', fullName: '' }
},
watch: {
firstName(val) { this.fullName = val + ' ' + this.lastName },
lastName(val) { this.fullName = this.firstName + ' ' + val },
}
两行 computed 能解决的事,写了两个 watch 还多出一个冗余 data,依赖一多直接失控。这是典型的该用 computed 的场景。
2. 在 computed 里发请求
computed 应该是纯函数,同样的依赖永远返回同样的结果。在里面发请求,一来返回值拿不到异步结果,二来每次重新计算都会触发请求,完全不可控。
3. watch 里改自己监听的值
容易写出无限循环。真要改,记得加条件判断出口。
速查表
| 场景 | 选择 |
|---|---|
| 模板里展示由其他数据算出来的值 | computed |
| 数据变了要发请求 / 存缓存 / 手动操作 DOM | watch |
| 需要拿到旧值做对比 | watch |
| 初始化就要执行一次 | watch + immediate |
| 派生值还要支持 v-model | computed setter |
一句话:能用 computed 的地方优先 computed,它是声明式的、可缓存的;watch 留给那些"真的要做点什么"的时刻。
看到这里了?如果这篇文章帮到过你
请我喝瓶可乐就好 🥤

评论0 条
还没有评论,来抢沙发~