【问题标题】:vue watch handler called without actual changes调用 vue watch 处理程序而不进行实际更改
【发布时间】:2019-11-05 18:23:27
【问题描述】:

在这个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
    );
  }
}

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

已编辑以添加更多细节:vuex store 中的数据已标准化。我们还使用了vue-grid-layout,它期望其layoutproperty 采用certain 非规范化格式。所以我们有一个 gridLayout getter 来执行 vuex -> vue-grid-layout 转换。观察这个 gridLayout getter 即使生成的 gridLayout 实际上没有改变,但其他细节发生了变化,例如 vuex 存储中的名称和其他与 vue-grid-layout 无关的对象键。

现在在上面的示例中,当this.counter 更改时,test 上的监视也会触发,即使 newValoldVal 是“相同的”。请注意,它们不是=====,而是与JSON.stringify(newVal) == JSON.stringify(oldVal) 中的“相同”。

有没有办法让我的watch 仅在发生实际更改时触发?实际上比较 JSON.stringify() 对我来说似乎效率低下,但我担心随着项目的增长会出现性能问题,因为我的手表可能会进行昂贵的操作,并且我想确保我不会遗漏任何东西。

【问题讨论】:

  • 您能否更详细地说明您将使用观察器的目的?根据您尝试做的事情,它可能会在您的架构决策中得到解决。我用 vue 创建了一个大型企业 SPA,由于性能原因,我最终删除了大多数 getter,最终将它们移动到一个混合库中,以便在上下文中调用,而不是在底层状态对象更新时调用。
  • @TimWickstrom:我已更新问题以根据要求添加更多详细信息。

标签: vue.js


【解决方案1】:

根据 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];
    }
  }
}

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

阅读更多:https://vuejs.org/v2/guide/computed.html#Computed-Caching-vs-Methods

【讨论】:

  • 而“如果(有变化){}”我猜你的意思是实现我自己的实际变化检测。这不完全等同于我在手表中对JSON.stringify(newVal) == JSON.stringify(oldVal) 的测试吗?
  • 是的,但是这里的根本区别是您正在删除 Vue 计算属性并只关注更改,并且正如您所说,自己在方法中处理逻辑,因此删除了不必要的计算属性。这将消除一个 observable 的开销。
  • 另外,如果您实际观察的是一个数组或对象,您可能需要添加一个深度观察器。请参阅更新的示例。 vuejs.org/v2/api/#watch
  • 我会接受您的回答,主要是因为“阅读更多”链接。我的问题是观察者开火太频繁,而不是太少。 deep: true 在我的实验中并没有减少它的触发频率。我将进行 JSON.stringify 比较以减少错误的观察者差异。
  • 我会接受您的回答,主要是因为“阅读更多”链接。我的问题是观察者开火太频繁,而不是太少。 deep: true 在我的实验中并没有减少它的触发频率。我将进行 JSON.stringify 比较以减少错误的观察者差异。感谢您的宝贵时间,@TimWickstrom。
猜你喜欢
  • 2021-05-28
  • 1970-01-01
  • 2018-05-14
  • 1970-01-01
  • 1970-01-01
  • 2011-03-25
  • 1970-01-01
  • 2012-09-28
  • 1970-01-01
相关资源
最近更新 更多