在商店中,我有一个操作来更新一些数据,该操作看起来像这样:
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])
},
因为所有这些数据都是动态的,所以我必须动态更改嵌套值,并且不能直接对属性进行硬编码。 数据如下:
fullreport: {
rooms: {
abc: {
items: [
{
type: "image-only",
items: [
{
label: "Main Image 1",
image: ""
},
{
label: "Main Image 2",
image: ""
}
]
}
]
}
}
}
当我分派动作时,在控制台中,我可以看到成功修改了子属性image
的值,但是如果我从Chrome内部的Vue DevTools访问VueX存储,则会看到该值在那里没有改变。这是控制台输出:
请,有人能说出为什么会发生吗?据我所知,数据正在成功更改,但是某种程度上状态没有显示出来,因此我的组件不会重新渲染。
我也尝试使用Vue.set
而不是简单的分配,但是还是没有运气:(
Vue.set(
state.fullReport.rooms[room].items[index].items[subIndex],
"image",
image
);
在 David Gard的回答之后,我尝试了以下操作:
我还使用Lodash _
(我知道制作对象的完整副本不好),这是突变代码块。
let fullReportCopy = _.cloneDeep(state.fullReport);
fullReportCopy.rooms[room].items[index].items[subIndex].image = image;
Vue.set(state, "fullReport", fullReportCopy);
现在在state.fullReport
是依赖项的计算属性中,我有一个console.log
,只要重新计算计算属性,它就打印出一个字符串。
每次执行此突变时,我都会看到计算出的属性记录了字符串,但是接收到的状态仍然没有改变,我猜Vue.set
只是告诉计算出的属性状态已改变,但是它实际上并没有改变。因此,我的组件的UI不变。
答案 0 :(得分:1)
问题在于,您必须以两种不同的方式填充数组和对象,因此,请考虑是否需要访问它们的本机方法。不幸的是,Vuex还不支持反应式地图。
此外,我还处理需要动态设置具有多个嵌套级别的属性的项目。一种解决方法是递归设置每个属性。
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);
}
}
我使用上面发布的解决方案的方式是这样的:
// in store/actions.js
export const actions = {
...
async prepareReactiveObject({ commit }, rawObject) {
commit('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
}
答案 1 :(得分:0)
不包括评论的良好做法。
您需要做的是:在对象更改时指示Vue(复杂的对象不起作用)。使用Vue.set。您需要设置整个对象:
Vue.set(
state,
"fullReport",
state.fullReport
);