Vue.draggable: Vuex + Vue.Draggable : [vuex] Do not mutate vuex store state outside...

Created on 29 Mar 2018  路  4Comments  路  Source: SortableJS/Vue.Draggable

Hello,

I've got an error message with Vuex and strict mode :

[Vue warn]: Error in callback for watcher "function () { return this._data.$$state }": "Error: [vuex] Do not mutate vuex store state outside mutation handlers."

(found in <Root>)

I've got the error every time I change the order of the elements (when I drop an element, only if the order has changed).

I have tried to simplify my code as much as possible and to reproduce the issue with JSFiddle, but the error doesn't show up : https://jsfiddle.net/bestiole/pmvwhwcq/4/
(I don't know if it doesn't exist or only if it doesn't display)

Therefore here is my code, but appart from fragmentation to files, I don't think there is any difference :

Tree.vue

<template>
    <div class="tree">
        <div v-for="(list, listName) in pages">
            <h3>List {{listName}}</h3>
            <draggable v-model="pages[listName]" :options="{group:{pull:true,put:true},animation: 150}" class="sortable-list">
                <div v-for="page in pages[listName]" :key="page.id" class="sortable">{{page.title}}</div>
            </draggable>
        </div>
    </div>
</template>

<script
    export default {
        name: 'tree',
        computed: {
            pages: {
                get() {
                    return this.$store.state.pages
                },
                set(value) {
                    this.$store.commit('setPages', value)
                }
            }
        }
    }
</script>

Store.js

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
    strict: true,
    state: {
        pages: {'menu' : [
                {'id' : 0, 'title' : 'home'},
                {'id' : 1, 'title' : 'about'},
                {'id' : 2, 'title' : 'contact'}
            ],
            'specials' : [
                {'id' : 3, 'title' : 'special'},
                {'id' : 4, 'title' : 'weirdo'},
            ]
        }
    },
    mutations: {
        setPages: (state, pages) => {
            state.pages = pages
        }
    }
});

I think the problem might be due to the first v-for loop on the pages object, and to the use of pages[listName] as a v-model but I think I'm supposed to handle it this way... (I'm new to Vuejs though)

Does anyone have an idea ? Am I doing something wrong ?

Most helpful comment

problem solved : https://forum.vuejs.org/t/vuex-vue-draggable-vuex-do-not-mutate-vuex-store-state-outside/30802/5

Here is my final code :

Structure.vue

<template>
    <div class="structure">
        <tree v-for="(value, key, index) in pages" :key="index" :name="key"></tree>
    </div>
</template>

<script>
    import tree from './Tree.vue'
    import axios from 'axios'

    export default {
        name: 'structure',
        components: {
            tree
        },
        computed: {
            pages: {
                get() {
                    return this.$store.state.pages
                },
                set(value) {
                    this.$store.commit('setPages', value)
                }
            }
        },
        created () {
            axios.get('/api/pages').then(response => {
                this.pages = response.data.pages
            })
        }
    }
</script>

Tree.vue

<template>
    <div>
        <h3>List {{name}}</h3>
        <draggable v-model="pagesGroup" :options="{group:{pull:true,put:true},animation: 150}" @end="handleDrop" class="sortable-list">
            <div v-for="page in pagesGroup" :key="page.id" class="sortable">{{page.title}}</div>
        </draggable>
    </div>
</template>

<script>
    export default {
        name: 'tree',
        props: [
            'name'
        ],
        computed: {
            pagesGroup: {
                get () {
                    return this.$store.state.pages[this.name]
                },
                set(value) {
                    this.$store.commit('setPagesGroup', {
                        value,
                        key: this.name,
                    })
                }
            }
        },
        methods: {
            handleDrop () {
                this.$store.dispatch('storePages')
            }
        },
        created () {
            console.log(this.pagesGroup);
        }
    }
</script>

store.js

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
    strict: true,
    state: {
        pages: {}
    },
    mutations: {
        setPages (state, pages) {
            state.pages = pages
        },
        setPagesGroup (state, { value, key }) {
            state.pages[key] = value
        }
    },
    actions: {
        storePages (context) {
            let jsonPages = JSON.parse(JSON.stringify(context.state.pages))
            console.log(jsonPages)
        }
    }
});

All 4 comments

problem solved : https://forum.vuejs.org/t/vuex-vue-draggable-vuex-do-not-mutate-vuex-store-state-outside/30802/5

Here is my final code :

Structure.vue

<template>
    <div class="structure">
        <tree v-for="(value, key, index) in pages" :key="index" :name="key"></tree>
    </div>
</template>

<script>
    import tree from './Tree.vue'
    import axios from 'axios'

    export default {
        name: 'structure',
        components: {
            tree
        },
        computed: {
            pages: {
                get() {
                    return this.$store.state.pages
                },
                set(value) {
                    this.$store.commit('setPages', value)
                }
            }
        },
        created () {
            axios.get('/api/pages').then(response => {
                this.pages = response.data.pages
            })
        }
    }
</script>

Tree.vue

<template>
    <div>
        <h3>List {{name}}</h3>
        <draggable v-model="pagesGroup" :options="{group:{pull:true,put:true},animation: 150}" @end="handleDrop" class="sortable-list">
            <div v-for="page in pagesGroup" :key="page.id" class="sortable">{{page.title}}</div>
        </draggable>
    </div>
</template>

<script>
    export default {
        name: 'tree',
        props: [
            'name'
        ],
        computed: {
            pagesGroup: {
                get () {
                    return this.$store.state.pages[this.name]
                },
                set(value) {
                    this.$store.commit('setPagesGroup', {
                        value,
                        key: this.name,
                    })
                }
            }
        },
        methods: {
            handleDrop () {
                this.$store.dispatch('storePages')
            }
        },
        created () {
            console.log(this.pagesGroup);
        }
    }
</script>

store.js

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
    strict: true,
    state: {
        pages: {}
    },
    mutations: {
        setPages (state, pages) {
            state.pages = pages
        },
        setPagesGroup (state, { value, key }) {
            state.pages[key] = value
        }
    },
    actions: {
        storePages (context) {
            let jsonPages = JSON.parse(JSON.stringify(context.state.pages))
            console.log(jsonPages)
        }
    }
});

@krodelabestiole Would you be so kind as to let me know what the data looks like and how it is formatted when it is returned from your axios call?

image

@alucidwolf sorry I don't work on this project anymore plus I switched to this tool : https://github.com/phphe/vue-draggable-nested-tree
it works great and I remember I had to change the server API format, plus some personal tweaks and I doubt it would be of any help.

maybe not is the best solution but i just put in /store/index.js -> export const strict = false

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Stetzon picture Stetzon  路  3Comments

iou90 picture iou90  路  3Comments

AlexandreBonneau picture AlexandreBonneau  路  3Comments

karam94 picture karam94  路  3Comments

Kuohao-wu picture Kuohao-wu  路  3Comments