Vuejs2-如何从服务器更新整个对象而不丢失反应性?

时间:2019-02-15 22:15:56

标签: vue.js vuejs2 vue-component

我有一个可以从数据库更新的对象列表。

因此,当我加载列表时,对象只有ID和名称。

当我单击一个对象时,我会加载其他任意长度的字段-这就是为什么我不使用列表中的对象加载它们的原因。

我发现更新对象时,保持反应性https://vuejs.org/v2/guide/reactivity.html可能很困难,因此我需要找到一些解决方法。

此代码几乎可以正常工作:

    axios.get('/api/news', item.id).then(function(response){
        if (response){
            Object.assign(item, response.data.item);
        }
    });

但是问题在于,从一开始就没有出现过的字段不再具有100%的反应性。发生的事情是,仅当我更改另一个以前的字段时,新字段才进行反应性更新。因此,如果我显示具有旧属性和新属性的2个文本字段,则如果更改第二个属性,则在更改第一个属性之前,该字段将不会更新。

我从组件中获得了项目对象:

data () {
        return {
            items: [], 
        }
},

            <div v-for="item in items" @click="selectItem(item)" >
                <span>{{item.name}}</span>
            </div>

然后将项目传递给函数selectItem。

加载新字段 并使它们保持反应性的正确模式是什么? (注意:我不能按字段分配字段-不管它是哪个对象,我都想重用相同的代码,所以我需要这样的解决方案来一次更新对象而不列出所有新字段。) / p>

注意。该代码在组件内部起作用。

2 个答案:

答案 0 :(得分:2)

完全修订后的文章:好的,您给出的示例使用一个数组,该数组具有its own caveats,尤其是您不能直接设置vm.items[indexOfItem] = newValue之类的值并使它起作用。

因此,您必须将Vue.set与数组一起用作第一个参数,将索引用作第二个参数。这是一个向对象项目添加name属性,然后使用Vue.set将项目设置为Object.assign创建的新对象的示例。

new Vue({
  el: '#app',
  data: {
    items: [{
      id: 1,
      other: 'data'

    }, {
      id: 2,
      other: 'thingy'
    }]
  },
  methods: {
    selectItem(parent, key) {
      const newObj = Object.assign({}, parent[key], {
        name: 'some new name'
      });

      Vue.set(parent, key, newObj);
      setTimeout(() => {parent[key].name = 'Look, reactive!';}, 1500);
    }
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
  <div v-for="item, index in items" @click="selectItem(items, index)">
    <span>{{item.name || 'empty'}}</span>
  </div>
  <pre>
  {{JSON.stringify(items, null, 2)}}
  </pre>
</div>

答案 1 :(得分:1)

看看Change-Detection-Caveats,如果您使用“常规分配”方法,Vue将无法检测到属性的添加或删除。
您必须使用Vue.set(object, key, value)
尝试如下操作:

axios.get('/api/news', item.id).then(function(response){
        if (response){
            let item = {}
            Vue.set(item, 'data', response.data.item)
        }
});

将比item.data重新激活。