IT이야기

Vuex: 작업 내에서 완전히 중첩된 상태 데이터를 변경할 수 없습니다.

cyworld 2022. 6. 13. 22:28
반응형

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 저장소에 액세스해도 값이 변경되지 않습니다.콘솔 출력은 다음과 같습니다.

여기에 이미지 설명 입력

누가 왜 이런 일이 일어나는지 말해줄래?데이터가 정상적으로 변경되고 있는 것은 알고 있습니다만, 왠지 상태가 표시되지 않기 때문에 컴포넌트가 재생되지 않습니다.

저도 한번 써봤어요.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는 변경되지 않습니다.

코멘트에서도 언급되어 있듯이, 스토어에서 깊게 중첩된 상태를 유지하면, 금방 복잡해집니다.

문제는 어레이와 오브젝트를 두 가지 방법으로 채워야 하기 때문에 네이티브 메서드에 액세스할 필요가 있는지 여부를 고려해야 한다는 것입니다.안타깝게도 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
}

댓글에 있는 모범 사례를 제외하고.

필요한 것은 개체가 변경될 때 Vue에 지시하는 것입니다(복잡한 개체는 반응하지 않음).Vue.set을 사용합니다.개체 전체를 설정해야 합니다.

   Vue.set(
     state,
     "fullReport",
     state.fullReport
   );

문서: https://vuejs.org/v2/api/ #Vue-set

언급URL : https://stackoverflow.com/questions/57907075/vuex-cant-change-deeply-nested-state-data-inside-actions

반응형