【问题标题】:How to trigger a change, when adding new property in object in VueJs?在 VueJs 的对象中添加新属性时如何触发更改?
【发布时间】:2018-12-26 22:29:54
【问题描述】:

我有以下 vuex 状态的初始结构(在 VueJS 项目中):

state: {
    level1prop: null
}

然后我动态地改变它,并将它变异成以下结构:

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

然后我将在level3prop 下添加"customKeyN": { /* this is some object N */ },对我来说重要的是在每次更改时触发观察者,该观察者正在观察从状态到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;

这是按照我想要的方式创建结构,但不会触发更改的观察者。按照here 的建议,我将我的代码重构为几种不同的方式,但它们都没有触发更改。这是我尝试过的最新选项的示例:

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);
...

在如此复杂的对象状态和如此多的嵌套级别中,有什么方法能够触发观察者进行更改?

【问题讨论】:

    标签: vue.js vuejs2 vue-component vuex watch


    【解决方案1】:

    如文档Object Change Detection Caveats 部分所述,您最好使用专门设计的 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>

    【讨论】:

      猜你喜欢
      • 2019-12-05
      • 2014-07-28
      • 2019-08-21
      • 2013-12-13
      • 1970-01-01
      • 2019-07-16
      • 1970-01-01
      • 2012-02-01
      • 1970-01-01
      相关资源
      最近更新 更多