vue的watch和computed到底哪里不同?这个问题在我看文档的时候没有很懂,以至于我就忘记了computed也会触发更新,结果悲剧了。。。吃一堑长一智,补课走起。
第一步必须是查看文档https://cn.vuejs.org/v2/guide/computed.html
明显上面这句话的含义是模版里面展示的数据如果需要复杂的处理后展示我们应该用计算属性(这个和监听更新并无关系),继续往下看,它给出了一个例子
<div id="example">
<p>Original message: "{{ message }}"</p>
<p>Computed reversed message: "{{ reversedMessage }}"</p>
</div>
var vm = new Vue({
el: '#example',
data: {
message: 'Hello'
},
computed: {
// 计算属性的 getter
reversedMessage: function () {
// `this` 指向 vm 实例
return this.message.split('').reverse().join('')
}
}
})
结果:
Original message: "Hello"
Computed reversed message: "olleH"
然后我们主动修改它的依赖数据message
vm.message = 'Goodbye'
console.log(vm.reversedMessage)
此时的结果是'eybdooG'。也就是说你可以像绑定普通属性一样在模板中绑定计算属性。Vue 知道 vm.reversedMessage 依赖于 vm.message,因此当 vm.message 发生改变时,所有依赖 vm.reversedMessage 的绑定也会更新。
然后我们把上面的效果用methods里面的方法去实现一下
<div id="example">
<p>Original message: "{{ message }}"</p>
<p>Computed reversed message: "{{ reversedMessage() }}"</p>
</div>
var vm = new Vue({
el: '#example',
data: {
message: 'Hello'
},
methods: {
reversedMessage () {
return this.message.split('').reverse().join('')
}
}
})
结果依然是:
Original message: "Hello"
Computed reversed message: "olleH"
也就是说我们两种方式结果是一样的(请相信每一个实现都会有差异,作者不会无缘无故实现几个没有差异的东西给你),这个时候去看文档吧~
上面清楚的说明了一个问题,computed是缓存的只要依赖的数据不更改他就不会重新计算更新,而methods里面的方法是每次刷新都会去执行的
最后来看看watch。官方给出了一句解释叫做当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的。
这句话怎么理解?看看它的例子就明白了,watch 选项允许我们执行异步操作 (访问一个 API),限制我们执行该操作的频率,并在我们得到最终结果前,设置中间状态
好了文档上就这么多,我们运用到实践中会是怎么样的呢
示例一:
根据路由的变化获取id去重新请求接口并展示数据(本质上就是watch路由的变化)
watch: {
$route () {
this.getList() // 这里为触发请求新列表的函数
}
}
分析:只监听一个值的变化,然后重新去计算
示例二:
进入页面之后要从store(vuex)里面去获取一个异步请求回来的数据(你不能确认开始获取是存在的)
computed: {
menu () {
return this.$store.state.storeMenu
}
}
分析:this.$store.state.storeMenu这个在进入页面的时候因为需要dispatch去触发一个异步的请求所以当你获取的时候不一定存在,而当store里面存在了因为menu计算依赖的数据变化它会重新计算填充。当然你可能会说如果我直接dispatch那个函数里加一个promise然后就可以保证拿到数据了,这个当然是,例如我在action里面写成下面的方式:
export const getMenuList = ({ commit }) => {
return new Promise((resolve, reject) => {
fetch('xxxxxx').then(res => {
commit(types.GET_MENU_LIST, {
menuList: res
})
resolve()
})
})
}
上面的方式确实可以保证你有数据,但是你如果有N处要进入页面就需要展示这个数据呢?不能多次dispatch吧
methods里面的方法就不再举例子了,它的好处绝对是可掌控,你可以主动的调用,而不是主动的去监听某个数据。
根据上面的学习和自己使用的经验做一个总结:
- computed是计算属性,是依赖其他属性计算得出的结果;watch是监听某一个值的变化执行对应的方法
- computed的值在getter执行后是会缓存的,只有在它依赖的属性值改变之后,下一次获取computed的值时才会重新调用对应的getter来计算;watch在每次监听的值变化时,都会执行回调。如果一个值依赖多个属性(多对一),用computed肯定是更加方便的。如果一个值变化后会引起一系列操作,或者一个值变化会引起一系列值的变化(一对多),用watch更加方便一些
- watch的回调里面会传入监听属性的新旧值,通过这两个值可以做一些特定的操作;computed通常就是简单的计算
- methods里面的方法不包含主动监听的能力,且相对于computed来讲没有缓存能力,每次会重新执行(在SPA切换的时候比较明显);但比较灵活,可以手动去调取
- 它们并没有哪个更底层。watch和computed的共同之处就是每个定义的属性都单独建立了一个Watcher对象,当然这个能力是方法所不具有的