admin管理员组文章数量:1291327
In the store, I have an action to update some data, the action looks like this:
setRoomImage({ state }, { room, index, subIndex, image }) {
state.fullReport.rooms[room].items[index].items[subIndex].image = image;
console.log(state.fullReport.rooms[room].items[index].items[subIndex])
},
Because all of this data is dynamic so I have to dynamically change the nested values and can't directly hard code the properties. The data looks like this:
fullreport: {
rooms: {
abc: {
items: [
{
type: "image-only",
items: [
{
label: "Main Image 1",
image: ""
},
{
label: "Main Image 2",
image: ""
}
]
}
]
}
}
}
When I dispatch the action, In the console I can see that the value of the sub-property image
is successfully mutated, but if I access the VueX store from the Vue DevTools inside Chrome, I see that value doesn't change there. Here is the console output:
Please, can somebody tell why is it happening? As I know that data is successfully changing, but somehow the state isn't showing it and hence my ponents do not rerender.
I also tried using Vue.set
instead of simple assignment, but still no luck :(
Vue.set(
state.fullReport.rooms[room].items[index].items[subIndex],
"image",
image
);
Edit:
Following David Gard's answer, I tried the following:
I am also using Lodash _
(I know making whole copies of objects isn't good), this is the mutation code block.
let fullReportCopy = _.cloneDeep(state.fullReport);
fullReportCopy.rooms[room].items[index].items[subIndex].image = image;
Vue.set(state, "fullReport", fullReportCopy);
Now In the puted property, where the state.fullReport
is a dependency, I have a console.log
which just prints out a string whenever the puted property is re-puted.
Every time I mit this mutation, I see the puted property logs the string, but the state it is receiving still doesn't change, I guess Vue.set
just tells the puted property that the state is changed, but it doesn't actually change it. Hence there is no change in my ponent's UI.
In the store, I have an action to update some data, the action looks like this:
setRoomImage({ state }, { room, index, subIndex, image }) {
state.fullReport.rooms[room].items[index].items[subIndex].image = image;
console.log(state.fullReport.rooms[room].items[index].items[subIndex])
},
Because all of this data is dynamic so I have to dynamically change the nested values and can't directly hard code the properties. The data looks like this:
fullreport: {
rooms: {
abc: {
items: [
{
type: "image-only",
items: [
{
label: "Main Image 1",
image: ""
},
{
label: "Main Image 2",
image: ""
}
]
}
]
}
}
}
When I dispatch the action, In the console I can see that the value of the sub-property image
is successfully mutated, but if I access the VueX store from the Vue DevTools inside Chrome, I see that value doesn't change there. Here is the console output:
Please, can somebody tell why is it happening? As I know that data is successfully changing, but somehow the state isn't showing it and hence my ponents do not rerender.
I also tried using Vue.set
instead of simple assignment, but still no luck :(
Vue.set(
state.fullReport.rooms[room].items[index].items[subIndex],
"image",
image
);
Edit:
Following David Gard's answer, I tried the following:
I am also using Lodash _
(I know making whole copies of objects isn't good), this is the mutation code block.
let fullReportCopy = _.cloneDeep(state.fullReport);
fullReportCopy.rooms[room].items[index].items[subIndex].image = image;
Vue.set(state, "fullReport", fullReportCopy);
Now In the puted property, where the state.fullReport
is a dependency, I have a console.log
which just prints out a string whenever the puted property is re-puted.
Every time I mit this mutation, I see the puted property logs the string, but the state it is receiving still doesn't change, I guess Vue.set
just tells the puted property that the state is changed, but it doesn't actually change it. Hence there is no change in my ponent's UI.
- 5 Just btw: You should avoid having such large nested objects in the store. See forum.vuejs/t/vuex-best-practices-for-plex-objects/10143/… – ssc-hrep3 Commented Sep 12, 2019 at 12:59
- 6 Actually inside your action you should mit some mutation to do this – Matheus Valenza Commented Sep 12, 2019 at 12:59
- 1 @MatheusValenza would that fix the current problem or just to follow the conventions? – Abbas Commented Sep 12, 2019 at 13:03
- 3 @NadirAbbas actions doesn't update state. Mutations does. Probably you are getting some warning about this. See vuex.vuejs – Matheus Valenza Commented Sep 12, 2019 at 13:06
- 2 did you try Vue.set instead of simple assign? – Matheus Valenza Commented Sep 12, 2019 at 13:11
2 Answers
Reset to default 6As mentioned in ments - it quickly gets plicated if you hold deeply nested state in your store.
The issue is, that you have to fill Arrays and Objects in two different ways, hence, consider whether you need access to their native methods or not. Unfortunately Vuex does not support reactive Maps yet.
That aside, I also work with projects that require the dynamic setting of properties with multiple nested levels. One way to go about it is to recursively set each property.
It's not pretty, but it works:
function createReactiveNestedObject(rootProp, object) {
// root is your rootProperty; e.g. state.fullReport
// object is the entire nested object you want to set
let root = rootProp;
const isArray = root instanceof Array;
// you need to fill Arrays with native Array methods (.push())
// and Object with Vue.set()
Object.keys(object).forEach((key, i) => {
if (object[key] instanceof Array) {
createReactiveArray(isArray, root, key, object[key])
} else if (object[key] instanceof Object) {
createReactiveObject(isArray, root, key, object[key]);
} else {
setReactiveValue(isArray, root, key, object[key])
}
})
}
function createReactiveArray(isArray, root, key, values) {
if (isArray) {
root.push([]);
} else {
Vue.set(root, key, []);
}
fillArray(root[key], values)
}
function fillArray(rootArray, arrayElements) {
arrayElements.forEach((element, i) => {
if (element instanceof Array) {
rootArray.push([])
} else if (element instanceof Object) {
rootArray.push({});
} else {
rootArray.push(element);
}
createReactiveNestedFilterObject(rootArray[i], element);
})
}
function createReactiveObject(isArray, obj, key, values) {
if (isArray) {
obj.push({});
} else {
Vue.set(obj, key, {});
}
createReactiveNestedFilterObject(obj[key], values);
}
function setValue(isArray, obj, key, value) {
if (isArray) {
obj.push(value);
} else {
Vue.set(obj, key, value);
}
}
If someone has a smarter way to do this I am very keen to hear it!
Edit:
The way I use the above posted solution is like this:
// in store/actions.js
export const actions = {
...
async prepareReactiveObject({ mit }, rawObject) {
mit('CREATE_REACTIVE_OBJECT', rawObject);
},
...
}
// in store/mutations.js
import { helper } from './helpers';
export const mutations = {
...
CREATE_REACTIVE_OBJECT(state, rawObject) {
helper.createReactiveNestedObject(state.rootProperty, rawObject);
},
...
}
// in store/helper.js
// the above functions and
export const helper = {
createReactiveNestedObject
}
Excluding the good practices on the ments.
That you need is: to instruct Vue when the object change (Complex objects are not reactive). Use Vue.set. You need to set the entire object:
Vue.set(
state,
"fullReport",
state.fullReport
);
Documentation: https://v2.vuejs/v2/api/#Vue-set
本文标签: javascriptVuex Can39t change deeply nested state data inside actionsStack Overflow
版权声明:本文标题:javascript - Vuex: Can't change deeply nested state data inside actions - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1741529572a2383672.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论