为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

阿晨1998 2021-10-14 14:06:32
在商店中,我有一个更新一些数据的操作,该操作如下所示: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 没有变化。
查看完整描述

2 回答

?
Helenr

TA贡献1780条经验 获得超4个赞

正如评论中提到的 - 如果您在商店中持有深度嵌套的状态,它很快就会变得复杂。

问题是,您必须以两种不同的方式填充数组和对象,因此,请考虑是否需要访问它们的本机方法。不幸的是,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

}


查看完整回答
反对 回复 2021-10-14
  • 2 回答
  • 0 关注
  • 251 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信