Vuex:无法更改动作内深度嵌套的状态数据

在商店中,我有一个更新一些数据的操作,该操作如下所示:



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 存储,我看到该值在那里没有改变。这是控制台输出:

http://img2.mukewang.com/6167c8fd00012baf05420144.jpg

拜托,有人能告诉为什么会这样吗?据我所知,数据正在成功更改,但不知何故状态没有显示它,因此我的组件不会重新渲染。


我也尝试使用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 没有变化。


阿晨1998
浏览 252回答 2
2回答

Helenr

正如评论中提到的 - 如果您在商店中持有深度嵌套的状态,它很快就会变得复杂。问题是,您必须以两种不同的方式填充数组和对象,因此,请考虑是否需要访问它们的本机方法。不幸的是,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.jsexport const actions = {  ...  async prepareReactiveObject({ commit }, rawObject) {    commit('CREATE_REACTIVE_OBJECT', rawObject);  },  ...}// in store/mutations.jsimport { helper } from './helpers';export const mutations = {  ...  CREATE_REACTIVE_OBJECT(state, rawObject) {    helper.createReactiveNestedObject(state.rootProperty, rawObject);  },  ...}// in store/helper.js// the above functions andexport const helper = {  createReactiveNestedObject}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

JavaScript