0

When payload.key is a key like foo, the code below is working fine, but how to update the value of a child key like foo.bar.a ?

export const mutations = {
  USER_UPDATE(state, payload) {
    console.log(payload);
    state.user = Object.assign({}, state.user, {
      [payload.key]: payload.value
    });
  }
}

=== EDIT ===

This is called by:

computed: {
  ...mapState(['user']),
  fooBarA: {
    get() {
      return this.$store.state.user.foo.bar.a
    },
    set(value) {
      this.$store.commit('USER_UPDATE', {
        key: 'foo.bar.a',
        value
      })
    }
  }
}
DevonDahon
  • 7,460
  • 6
  • 69
  • 114

2 Answers2

1

You are replacing the whole state.user Object reference with a new Object, which destroys reactivity.

This simplified code does not demonstrate the need to use Object.assign, so in this cas you can simply:

export const mutations = {
  USER_UPDATE(state, payload) {
    state.user[payload.key] = payload.value
  }
}

Which keeps the original state.user Object reference.

Iyashi
  • 542
  • 4
  • 19
  • Thanks for this hint. However, `payload.key` is creating a variable like this `state.user['foo.bar.a']`, while I need `state.user.foo.bar.a`, any way to convert this string into children keys ? – DevonDahon Oct 26 '20 at 13:22
  • 1
    Not a trivial task, but here's a very good explanation: https://stackoverflow.com/questions/6393943/convert-javascript-string-in-dot-notation-into-an-object-reference . This does not exactly do what you want, but should point in the right direction. – Iyashi Oct 26 '20 at 13:27
  • What I want to add here: I use `vuex` with primitives and arrays only to avoid problems like this. It's easier said than done, I know. But if you're able to create `user` as a `vuex.module` and thus, flatten it to primitives, all of this is resolved. Probably a tedious task, but for me it was always worth it. – Iyashi Oct 26 '20 at 13:31
  • The post you sent discourage to do things the way I'm doing it. Is there maybe something I can change in the way I'm calling the mutation ? (I have updated my post to show how the mutation is called). – DevonDahon Oct 26 '20 at 13:33
  • I'm sorry, but I think there's no _nice_ way to do this :-/ It is best practice to avoid complex structures in `vuex` mainly for this reason. You probably have to flatten your data structure and add mutators for all of `user`s mutatable data. Here again, I give you the hint to use `vuex` modules, which somewhat allowes nested Objects, but you have to add all the mutators anyway. – Iyashi Oct 26 '20 at 13:42
  • Sorry, I just deleted my answer... the problem came from my Vuex tool not recording the changes. – DevonDahon Oct 26 '20 at 14:57
  • So I deleted mine :p – Iyashi Oct 26 '20 at 14:58
1

I have an approach that works.

Where the payload.key is "foo.bar.a"

const mutations = {
  UPDATE_USER(state, payload) {
    const setter = new Function(
      "obj",
      "newval",
      "obj." + payload.key + " = newval;"
    );
    let user = { ...state.user };
    setter(user, payload.value);
    state.user = user;
  }
};

Demo https://codesandbox.io/s/vuex-store-nested-key-setter-x1n00

Inspiration from https://stackoverflow.com/a/30360979/815507

Kunukn
  • 2,136
  • 16
  • 16