Search code examples
javascriptrecursionnestedvue.jsvuex

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


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?


Solution

  • After consulting with some other devs later that evening we came with few ways how to achieve it. Because the data are nested in a tree and I access the nodes in recursive manner, I need to either get the path to the specific node, so for example pass the index of a node as a property, then add the child index while repeating that in every node recursively, or pass just the id of a node and then run the recursive loop in the action in order to toggle its properties.

    More optimal solution could be flattening the data structure, hence avoiding the need for a recursion. The node would be then accessible directly via an id.