Vue.js + Vuex: how to change the state of nested elements?

let's say I have a tree:

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

The tree is stored in the module through Vuex under the key "tree" and looped through the following recursive component called the "recursive element":

 <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 switch the item property 'is_whatever', so I am attaching 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 on it, it works, but emits the following

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

How can I implement it without this error? I don’t see a way to send an event or emit an event at the beginning of the tree, because it is nested and recursive, so I don’t have a path to a specific element, right?

+5
source share
2 answers

After consulting with some other developers later in the evening, we came in several ways to achieve this. Since the data is nested in the tree, and I access the nodes in a recursive way, I need to either get the path to a specific node, for example, pass the index of the node property as a property, and then add a child index, repeating that in each node is recursive. or pass only the node identifier, and then run the recursive loop in action to switch its properties.

A more optimal solution may be to smooth the data structure, which avoids the need for recursion. node will then be available directly through id.

+1
source

Right now, you are changing the state object directly by calling item.is_whatever = !item.is_whatever , you need to create a mutation function that will perform this operation to ensure proper reactivity:

 const store = new Vuex.Store({ state: { /* Your state */ }, mutations: { changeWhatever (state, item) { const itemInState = findItemInState(state, item); // You'll need to implement this function itemInState.is_whatever = !item.is_whatever } } }) 

Then you need to set this.$store.commit('changeWhatever', item) as an action in your view that will fire with a click.

+1
source

Source: https://habr.com/ru/post/1270837/


All Articles