vue 中 深度监听数据变化

2020-12-01  本文已影响0人  kopsht

原文 [https://michaelnthiessen.com/how-to-watch-nested-data-vue/]

本文解决:

  1. watch 与 computed 应该使用哪个;
  2. watch中绑定object或array时,数据没有更新(deep);
  3. prop的默认值(default)没有触发watch函数(immediate);
  4. 多个prop更新时触发同一个处理函数

watch 方法是什么

在Vue中,我们可以[监视属性何时更改]并对响执行一些操作。

例如,如果colour发生变化,我们console一些文字:

export default {
  name: 'ColourChange',
  props: ['colour'],
  watch: {
    colour()
      console.log('The colour has changed!');
    }
  }
}

这些观察者使我们能够做各种有用的事情。

但是很多时候,我们本来只需要使用computed实际上却使用率watch。

应该使用watch还是computed?

watched通常会与computed属性混淆,因为它们的运作方式相似。知道何时使用哪一个更难。

但是我想出了一个很好的经验法则。

改变state使用computed,需要副作用使用watch。

任何异步或发生在component外的,都算是副作用

常见的例子有:

这些不会直接影响组件的被认为是副作用

如果不执行此类操作,需要响应其他变化更新计算时,computed确实非常有用。

但有时,computed没什么意义。比如渲染<template>的话data就够了。如果需要更新它以响应属性更改,则需要使用观察程序。

注意:使用watch更新状态时要小心。这意味着您的组件和父组件都在直接或间接地更新相同的状态。This can get very ugly very fast

观察嵌套数据—数组和对象

如果已经确定你需要使用watch而不是computed,但是wach 一个数组或一个对象没能按预期工作
为什么?

假设有一个数组数组:

const array = [1, 2, 3, 4];
// array = [1, 2, 3, 4]

现在,通过push来更新数组:

array.push(5);
array.push(6);
array.push(7);
// array = [1, 2, 3, 4, 5, 6, 7]

问题是:array变了吗?

虽然array的内容变了,但是这个array变量的指针指向的内存地址并没有变,所以这个array容器并没有变化。因此,当watch一个数组或对象时,Vue不知道您已经更改了array或object 内部的 内容。您必须告诉Vue在观察更改时希望它需要监控容器的内部。

您可以通过在watch上将设置deeptrue并写handler 方法来实现它。

export default {
  name: 'ColourChange',
  props: {
    colours: {
      type: Array,
      required: true,
    },
  },
  watch: {
    colours: {
      // This will let Vue know to look inside the array
      deep: true,

      // We have to move our method to a handler field
      handler()
        console.log('The list of colours has changed!');
      }
    }
  }
}

现在,Vue能够监控容器的内部的内容了。

immediate

观察者仅在prop的值更改时才会触发,但我们通常也需要在启动时触发一次。

假设我们有一个MovieData组件,它根据movieprop设置服务器获取数据的地址:

  name: 'MovieData',
  props: {
    movie: {
      type: String,
      required: true,
    }
  },
  data() {
    return {
      movieData: {},
    }
  },

  watch: {
    // Whenever the movie prop changes, fetch new data
    movie(movie) {
      // Fetch data about the movie
      fetch(`/${movie}`).then((data) => {
        this.movieData = data;
      });
    }
  }
}

每当movie更新时,watcher就会触发,并获取新数据。

但是这里还有一个问题。当页面加载时,movie会被设置默认值。但是由于prop还没有改变,所以watch没有被触发。这意味着movie更新之前,不会加载数据。

那么,如何让我们的watch在页面加载后立即触发?

我们将其设置immediate为true,然后将需要触发的函数放在handler中:

watch: {
  // Whenever the movie prop changes, fetch new data
  movie: {
    // Will fire as soon as the component is created
    immediate: true,
    handler(movie) {
      // Fetch data about the movie
      fetch(`/${movie}`).then((data) => {
        this.movieData = data;
      });
    }
  }
}

好的,现在我认为是时候介绍一下handler了。

handler

Watchers有三个不同的属性:

我们只是看了前两个,第三个也不难。您可能已经在使用它,而没有意识到它。

在prop变更时将会调用handler方法

如果如果不需要immediate或者是deep,我们一般写如下的代码:

watch: {
  movie: {
    handler(movie) {
      // Fetch data about the movie
      fetch(`/${movie}`).then((data) => {
        this.movieData = data;
      });
    }
  }
}

而是使用它的简写形式:

watch: {
  movie(movie) {
    // Fetch data about the movie
    fetch(`/${movie}`).then((data) => {
      this.movieData = data;
    });
  }
}

最酷的是Vue还允许我们使用String来命名处理函数。如果我们想在两个或更多props发生变化时写处理函数,这很有用。

以我们的movie组件示例为例,假设我们同时基于movieactor两个prop来获取数据:

watch: {
  // Whenever the movie prop changes, fetch new data
  movie {
    handler: 'fetchData'
  },
  // Whenever the actor changes, we'll call the same method
  actor: {
    handler: 'fetchData',
  }
},

methods: {
  // Fetch data about the movie
  fetchData() {
    fetch(`/${this.movie}/${this.actor}`).then((data) => {
      this.movieData = data;
    });
  }
}
上一篇下一篇

猜你喜欢

热点阅读