Как вызвать изменение при добавлении нового свойства в объект в VueJs?

У меня следующая начальная структура состояния vuex (в проекте VueJS):

state: {
    level1prop: null
}

А затем я изменяю его динамически и превращаю в следующую структуру:

state: {
    level1prop: {
        level2prop: {
            level3prop: {
                "customKey1": { /* this is some object 1 */ },
                "customKey2": { /* this is some object 2 */ },
                ...
            }
        }
    }
}

Затем я добавлю "customKeyN": { /* this is some object N */ } под level3prop, и для меня важно при каждом изменении запускать наблюдатель, который следит за изменениями в level1prop из состояния.

Изначально в своей мутации я делал это обновление следующим образом:

if (!state.hasOwnProperty("level1prop"))
    state["level1prop"] = {};
else if (state["level1prop"] === null || state["level1prop"] === undefined)
    state["level1prop"] = {};

if (!state["level1prop"].hasOwnProperty("level2prop"))
    state["level1prop"]["level2prop"] = {};
else if (state["level1prop"]["level2prop"] === null || state["level1prop"]["level2prop"] === undefined)
    state["level1prop"]["level2prop"] = {};

if (!state["level1prop"]["level2prop"].hasOwnProperty("level3prop"))
    state["level1prop"]["level2prop"]["level3prop"] = {};
else if (state["level1prop"]["level2prop"]["level3prop"] === null || state["level1prop"]["level2prop"]["level3prop"] === undefined)
    state["level1prop"]["level2prop"]["level3prop"] = {};

let payloadObj = {  "customKey1": { /* this is some object 1 */ }  };
state["level1prop"]["level2prop"]["level3prop"] = payloadObj;

И это создает структуру так, как я хочу, но наблюдатель изменений не запускается. Следуя советам здесь, я реорганизовал свой код несколькими способами, но ни один из них не вызывает изменений. Вот пример последнего варианта, который я пробовал:

if (!state.hasOwnProperty("level1prop"))
    state = Object.assign(state, { "level1prop" : {} });
else if (state["level1prop"] === null || state["level1prop"] === undefined)
    state = Object.assign(state, { "level1prop" : {} });

if (!state["level1prop"].hasOwnProperty("level2prop"))
    state["level1prop"] = Object.assign(state["level1prop"], { "level2prop" : {} });
else if (state["level1prop"]["level2prop"] === null || state["level1prop"]["level2prop"] === undefined)
    state["level1prop"] = Object.assign(state["level1prop"], { "level2prop" : {} });

if (!state["level1prop"]["level2prop"].hasOwnProperty("level3prop"))
    state["level1prop"]["level2prop"] = Object.assign(state["level1prop"]["level2prop"], { "level3prop" : {} });
else if (state["level1prop"]["level2prop"]["level3prop"] === null || state["level1prop"]["level2prop"]["level3prop"] === undefined)
    state["level1prop"]["level2prop"] = Object.assign(state["level1prop"]["level2prop"], { "level3prop" : {} });

let payloadObj = {  "customKey 1": { /* this is some object 1 */ }  };
state["level1prop"]["level2prop"]["level3prop"] = Object.assign(state["level1prop"]["level2prop"]["level3prop"], payloadObj);

Опять же, это создает структуру, которая мне нужна, но наблюдатель все еще не запускается. Еще несколько вариантов, которые я пробовал, но не вызвал изменения:

...
state["level1prop"]["level2prop"]["level3prop"] = Object.assign({}, state["level1prop"]["level2prop"]["level3prop"], payloadObj);
...

и

...
Object.assign(state["level1prop"]["level2prop"]["level3prop"], payloadObj);
...

Есть ли способ запустить наблюдатель для изменений в таком сложном состоянии объекта с таким количеством вложенных уровней?


person delux    schedule 18.07.2018    source источник


Ответы (1)


Как объясняется в разделе при обнаружении изменения объекта документации , вам лучше использовать специально разработанный сеттер Vue Vue.set, чтобы позже добавлять подуровни к вашему состоянию.

Затем убедитесь, что ваш наблюдатель указывает параметр deep, чтобы он правильно запускался, когда ваш дополнительный -уровни меняются.

const store = new Vuex.Store({
  state: {
    level1prop: null,
  },
});

const state = store.state;

if (!state["level1prop"])
  Vue.set(state, "level1prop", {})

if (!state["level1prop"]["level2prop"])
  Vue.set(state["level1prop"], "level2prop", {})

if (!state["level1prop"]["level2prop"]["level3prop"])
  Vue.set(state["level1prop"]["level2prop"], "level3prop", {})

let payloadObj = {
  "customKey1": {
    hello: "world",
  },
};
state["level1prop"]["level2prop"]["level3prop"] = payloadObj;

setTimeout(() => {
  // Change an already existing key.
  state["level1prop"]["level2prop"]["level3prop"].customKey1.hello = "too";
}, 1000);

setTimeout(() => {
  // To add or remove keys, make sure to use again Vue.set or Vue.delete.
  state["level1prop"]["level2prop"]["level3prop"].customKey1.hello = "too";
  Vue.set(state["level1prop"]["level2prop"], "level3propSibling", {
    hi: "again",
  });
}, 2000);


new Vue({
  store: store,
  watch: {
    "$store.state": {
      // Make sure you specify the `deep` option
      deep: true,
      handler() {
        console.log(store.state);
      },
    },
  },
});
<script src="https://unpkg.com/vue@2"></script>
<script src="https://unpkg.com/vuex@3"></script>

person ghybs    schedule 19.07.2018