vue watch handler 被调用但没有实际的改变

Pet*_*rch 5 vue.js

在此codepen中有一个计数器,可以通过“incr”链接递增。

我现在有一个计算属性和一个手表:

computed: {
  test() {
    let unused = this.counter;
    return [42];
  }
},
watch: {
  test(val, old) {

    // Should I avoid firing when nothing actually changed
    // by implementiong my own poor-man's change detection?
    //
    // if (JSON.stringify(newVal) == JSON.stringify(oldVal))
    //   return;

    console.log(
      'test changed',
      val,
      old
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

也许是一个人为的例子,但实际上这是一个计算,其中真实数据被减少(在 vuex getter 中),并且最常见的是,即使某些数据发生变化,减少的数据也不会改变。

编辑以添加更多详细信息:vuex 中的数据store已标准化。我们还使用vue-grid-layout,它期望其layout属性采用某种非标准化格式。所以我们有一个gridLayoutgetter 来执行 vuex -> vue-grid-layout 转换。即使生成的 gridLayout 实际上没有改变,但其他细节发生了变化(例如 vuex 存储中的名称和其他与 vue-grid-layout 对象键无关的名称和其他不相关的内容),也会触发此 gridLayout getter。

在上面的例子中,当this.counter发生变化时,手表也会test起火,即使 和newValoldVal“相同的”。它们不是=====介意你,但与 中的“相同” JSON.stringify(newVal) == JSON.stringify(oldVal)

有什么办法watch只有在发生实际变化时才能点燃我的火?实际上,比较JSON.stringify()对我来说似乎效率低下,但随着我的项目不断增长,我担心性能问题,因为我的手表可能会执行昂贵的操作,并且我想确保我不会错过任何东西。

Tim*_*rom 0

根据 Vue.js 文档,当响应式依赖项发生更改时,计算属性就会重新评估。

在你的情况下,反应性依赖是this.counter

您可以通过调用方法而不是计算属性来获得相同的结果。

只需更改您的组件架构即可:

data () {
  return: {
    counter: 0,
    obj: {},
    output: null
  }
},
watch: {
  counter(val, old) {
    // Alternatively you could remove your method and do something here if it is small
    this.test(val);
  },
  // Deep watcher
  obj: {
    handler: function (val, oldVal) {
        console.log(val);
        console.log(oldVal);
        this.test(val);
    },
    deep: true
},
  }
},
methods: {
  test() {
    let unused = this.counter;
    if (something changed)
      this.output = [42];
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

现在在您的模板(或其他计算属性)中output是反应性的

了解更多: https: //v2.vuejs.org/v2/guide/compulated.html#Compulated-Caching-vs-Methods