对象数组 - 在 Vue.js 生态系统中更新对象的正确方法

问题描述:

我不确定问题到底出在哪里,但我会看看是否有人可以帮助我了解我的代码出了什么问题.

I'm not sure exactly where the issue lies with this, but I'm going to see if anyone can help me understand what is going wrong with my code.

我正在使用 Vuex 存储来跟踪一些不断变化的状态.我这样做如下:

I am utilising the Vuex store, to keep a track of some state that is constantly mutating. I'm doing this as follows:

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    id: 0,
    contentBlocks: []
  },
  mutations: {
    addContentBlock(state, contentBlock) {
      contentBlock.id = state.id
      state.contentBlocks.push(contentBlock)
      state.id += 1
    },
    updateContentBlock(state, contentBlock) {
      state.contentBlocks[contentBlock.id] = contentBlock
    },
    removeContentBlock(state, contentBlock) {
      state.contentBlocks.splice(state.contentBlocks.indexOf(contentBlock), 1);
    }
  }
})

创建和删除块似乎工作正常.

Creating and deleting blocks seems to work fine.

但是,在更新块时 - 出了点问题.我可以通过显示 contentBlocks 实例的日志来解释出了什么问题的唯一方法:

However, when updating a block - something is going wrong. The only way I can explain what is going wrong is by showing the log of the contentBlocks instance:

在上面的截图中可以看到,已经更新的对象实例(上面例子中的索引1)不太正确,它似乎不是一个观察者对象?

As you can see in the above screenshot, the object instances that has been updated (index 1 in the above example) is not quite correct, it doesn't seem to be an Observer object?

失败的一行是:

state.contentBlocks[contentBlock.id] = contentBlock

所以,我想知道......这应该是什么?

So, I'm wondering...what should this be?

更新:

根据以下答案的建议,我有以下几点:

On the advise of the below answer I have the following:

updateContentBlock(state, contentBlock) {
  const index = state.contentBlocks.findIndex(block => block.id === contentBlock.id)
  Vue.set(state.contentBlocks, index, contentBlock)
},
removeContentBlock(state, contentBlock) {
  const index = state.contentBlocks.findIndex(block => block.id === contentBlock.id)
  state.contentBlocks.splice(index, 1, contentBlock)
}

在我的店里.但是,这不会删除 contentBlocks.

in my store. However, this isn't removing contentBlocks.

我已尝试将建议的代码更改为:

I've tried changing the suggested code to:

state.contentBlocks.splice(index, 1)

但这会导致一些奇怪的行为.例如,我有索引 0、1 和 2 的块……我变异以删除索引 0.一切看起来都不错 - 我只剩下索引 1 和 2 处的 contentBlocks.然而它们带有来自 0 和 1 的内容???

But this is causing some odd behaviour. For example, I have blocks of indices 0, 1 and 2 ... I mutate to remove index 0. All looks good - I have only the contentBlocks at indices 1 and 2 left. Yet they come with the content from 0 and 1 ???

这是 Vue 对数组的反应性的限制.

This is a limitation of Vue's reactivity regarding arrays.

见#2 of 为什么 DOM 没有更新?

当您通过直接设置索引(例如 arr[0] = val)或修改其长度属性来修改数组时.类似地,Vue.js 无法获取这些更改.始终使用 Array 实例方法修改数组,或完全替换它.Vue 提供了一个方便的方法 arr.$set(index, value),它是 arr.splice(index, 1, value)

When you modify an Array by directly setting an index (e.g. arr[0] = val) or modifying its length property. Similarly, Vue.js cannot pickup these changes. Always modify arrays by using an Array instance method, or replacing it entirely. Vue provides a convenience method arr.$set(index, value) which is syntax sugar for arr.splice(index, 1, value)

您可以通过在模块中使用 Vue.setArray.splice 来解决此问题:

You can solve this by using Vue.set or Array.splice in your module:

import Vue from 'vue'

// find the block's index in the array
const index = state.contentBlocks.findIndex(block => block.id === contentBlock.id)

// using Vue.set
Vue.set(state.contentBlocks, index, contentBlock)

// using Array.splice
state.contentBlocks.splice(index, 1, contentBlock)