美文网首页vue
谨慎使用vue.watch

谨慎使用vue.watch

作者: 浩神 | 来源:发表于2018-06-18 16:09 被阅读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回调,这里包括:
    • 属性增减(delete 或直接新增属性)
    • 修改某一个属性的值(需要添加deep: true的选项)
    1. 如果watch的对象赋值给一个内部所有属性和属性的值相等的新对象,也会触发更新。
    2. Vue内部已经重写了数组的一些方法,如: splice, shift, push pop等,但下面的情况不能捕获更新:
    • 直接用index去更新数组,如 cities[1] = 'sss'
    • 直接修改cities的长度 如cities.length = 0

    相关文章

      网友评论

        本文标题:谨慎使用vue.watch

        本文链接:https://www.haomeiwen.com/subject/dajbeftx.html