使用VueJS更新对象中的多个道具时如何引起反应?

Aus*_*oss 5 javascript vue.js vue-component vuex vuejs2

在构建我的应用程序时,我目睹了一些奇怪的行为,其中 dom 的一部分没有对输入做出正确的反应。突变正在注册,状态正在改变,但 DOM 中的 prop 没有。我注意到当我回去时,在 html 中编辑了一个新的空白行,然后回来了,它现在正在显示新的道具。但是我必须编辑,保存,然后返回文档才能看到状态的任何新更改。

所以状态正在更新,但 Vue 没有对变化做出反应。这就是为什么我认为原因:https : //vuejs.org/v2/guide/reactivity.html#For-Objects

Vue 无法检测属性的添加或删除。由于 Vue 在实例初始化期间执行 getter/setter 转换过程,因此数据对象中必须存在一个属性,以便 Vue 对其进行转换并使其具有反应性

有时您可能希望为现有对象分配多个属性,例如使用 Object.assign() 或 _.extend()。但是,添加到对象的新属性不会触发更改。在这种情况下,创建一个具有原始对象和 mixin 对象属性的新对象

我所在州的 Object 是js-libp2p. 每当libp2p实例执行某些操作时,我都需要定期更新状态中的对象。我是通过执行突变来做到这一点的

syncNode(state, libp2p) {
    state.p2pNode = libp2p
}
Run Code Online (Sandbox Code Playgroud)

libp2p我试图通过更改 DOM 来响应的对象的当前实例在哪里state.p2pNode?我不能使用$set,这是用于单值编辑,我认为.assign.extend不会工作,因为我正在尝试替换整个对象树。

为什么会有这个限制,是否有针对这个特定问题的解决方案?

Ale*_*xMA 2

我相信你的问题比新属性分配的基本规则更复杂。但这个答案的前半部分涉及基本规则。

要回答为什么 Vue 对于如何正确地将新属性分配给响应式对象有一些限制,这可能与该语言的性能和限制有关。理论上,Vue可以不断地遍历其响应式对象来搜索新属性,但性能可能会很糟糕。

无论如何,Vue 3 的新编译器应该能够更轻松地处理这个问题。在此之前,您链接的文档可为大多数情况提供正确的解决方案(请参阅下面的示例)。

var app = new Vue({
  el: "#app",
  data() {
    return {
      foo: {
        person: {
          firstName: "Evan"
        }
      }
    };
  },
  methods: {
    syncData() {
      // Does not work
      // this.foo.occupation = 'coder';

      // Does work (foo is already reactive)
      this.foo = {
        person: {
          firstName: "Evan"
        },
        occupation: 'Coder'
      };

      // Also works (better when you need to supply a 
      // bunch of new props but keep the old props too)
      // this.foo = Object.assign({}, this.foo, {
      //  occupation: 'Coder',
      // });      
    }
  }
});
Run Code Online (Sandbox Code Playgroud)
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
  Hello {{foo.person.firstName}} {{foo.occupation}}!
  <button @click="syncData">Load new data</button>
</div>
Run Code Online (Sandbox Code Playgroud)

更新:Dan 的答案很好——在大多数情况下可能比我的更好,因为它考虑了 Vuex。考虑到当您使用他的解决方案时您的代码仍然无法工作,我怀疑p2pNode有时会发生自身突变(Vuex 期望该对象中的所有突变都经过官方提交)。鉴于它似乎有生命周期挂钩(例如libp2p.on('peer:connect'),如果是这种情况我不会感到惊讶。您最终可能会竭尽全力试图在后台悄悄变异的节点上获得完美的反应性。

如果是这种情况,并且 libp2p 没有提供libp2p.on('update')可以通知 Vuex 更改的钩子,那么您可能想要实现一种基本的游戏状态循环,并简单地告诉 Vue 在短暂睡眠后每隔一段时间重新计算所有内容。请参阅/sf/answers/2841081071//sf/answers/2793996481/。这有点小技巧(至少是一种知情的技巧),但在短期内它可能会让你的生活变得更加轻松,直到你解决这个棘手的错误,并且不应该有任何闪烁。