Vue.js + Vuex: How to mutate nested item state?

Viewed 5355

let's say I have following tree:

[
    {
        name: 'asd',
        is_whatever: true,
        children: [
            {
                name: 'asd',
                is_whatever: false,
                children: [],
            },
        ],
    },
],

The tree is stored in a module via Vuex under key 'tree' and looped through with following recursive component called 'recursive-item':

<li class="recursive-item" v-for="item in tree">
    {{ item.name }}

    <div v-if="item.is_whatever">on</div>
    <div v-else>off</div>

    <ul v-if="tree.children.length">
        <recursive-item :tree="item.children"></recursive-item>
    </ul>
</li>

Now i want to toggle item's property 'is_whatever', so i attach a listener

    <div v-if="item.is_whatever" 
         @click="item.is_whatever = !item.is_whatever">on</div>
    <div v-else>off</div>

When i click it, it works, but emits following

"Error: [vuex] Do not mutate vuex store state outside mutation handlers."
[vuex] Do not mutate vuex store state outside mutation handlers.

How am I supposed to implement it without this error? I can see no way how to dispatch an action or emit event to the top of the tree because it's nested and recursive, so I haven't got a path to the specific item, right?

3 Answers

There is a debatable solution, but I'll just leave it here.

State:

state: {
  nestedObject: {
    foo: {
      bar: 0
    }
  }
}

There is Vuex mutation:

mutateNestedObject(state, payload) {
  const { callback } = payload;
  callback(state.nestedObject);
},

And this is an example of use in a component:

this.$store.commit('mutateNestedObject', {
  callback: (nestedObject) => {
    nestedObject.foo.bar = 1;
  },
});
Related