问题
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.
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.
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:
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?
The failing line is:
state.contentBlocks[contentBlock.id] = contentBlock
So, I'm wondering...what should this be?
Update:
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)
}
in my store. However, this isn't removing contentBlocks.
I've tried changing the suggested code to:
state.contentBlocks.splice(index, 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 ???
回答1:
This is a limitation of Vue's reactivity regarding arrays.
See #2 of Why isn’t the DOM updating?
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 methodarr.$set(index, value)
which is syntax sugar forarr.splice(index, 1, value)
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)
来源:https://stackoverflow.com/questions/52132321/array-of-objects-correct-way-of-updating-an-object-within-the-vue-js-ecosystem