vue

谨慎使用vue.watch

2018-06-18  本文已影响3584人  浩神

如果不是对Vue的响应式原理了如指掌,请谨慎使用watch
本文不讨论watch一个基本类型的数据,因为这种情形几乎不会出现意料之外的表现。
试着看一下下面的代码:

<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>
<script src="https://cdn.bootcss.com/vue/2.5.16/vue.min.js"></script>
<script>
  new Vue({
    data() {
      return {
        city: {id: 1, name: '北京'}
      }
    },
    watch: {
      city() {
        console.log('city changed')
      }
    },
    created() {
      this.city = {id: 1, name: '北京'}
    }
  })
</script>
</body>
</html>

会触发watch吗?
会的,因为在created方法里面重新给city赋值了一个对象,city前后的指向不同了
以上这点代码出自一个有三年工作经验的前端程序员。他期望city发生变化之后,重新请求跟city相关的数据,他并没有意识到重新赋值给this.city一个相同的对象也会触发更新。所以在页面加载的时候就连发了两个city相关数据的请求。

这就是我写这篇文章的原因,我们考虑更多的情景。

下面这种情况会触发watch吗?

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>
<script src="https://cdn.bootcss.com/vue/2.5.16/vue.min.js"></script>
<script>
  const city = {id: 1, name: '北京'}
  new Vue({
    data() {
      return {
        city
      }
    },
    watch: {
      city() {
        console.log('city changed')
      }
    },
    created() {
      this.city.name = 'Beijing'
    }
  })
</script>

</body>
</html>

不会触发, 因为created方法执行之后, city的指向没有变
如果我们期望捕获这种更新,应该这样写代码:

 watch: {
      city: {
        handler: () => console.log('city changed'),
        deep: true
      }
    }

将选项deep设为true能让vue捕获对象内部的变化。

下面讨论一下watch一个数组:

  new Vue({
    el: '#body',
    data() {
      return {
        cities: ['beijing', 'tianjin']
      }
    },
    watch: {
      cities() {
        console.log('cities changed')
      }
    }
  })

那下面哪些操作会触发cities的watch回调呢?

this.cities = ['beijing', 'tianjin']
this.cities.push('xiamen')
this.cities = this.cities.slice(0, 1)
this.cities[0] = 'dali'
this.cities.splice(0, 1)
this.cities.length = 0

答案是只有最后两行不会触发。

总结

  1. 如果watch的是一个对象,reference equal的变化不会触发watch回调,这里包括:
  1. 如果watch的对象赋值给一个内部所有属性和属性的值相等的新对象,也会触发更新。
  2. Vue内部已经重写了数组的一些方法,如: splice, shift, push pop等,但下面的情况不能捕获更新:
上一篇下一篇

猜你喜欢

热点阅读