1
votes

I thought I understood the correct way to load inital state data from Vuex into the local data of a component, but why is this giving me “[vuex] do not mutate vuex store state outside mutation handlers.” errors! I am using a mutation handler!

I want my component data to start empty, unless coming back from a certain page (then it should pull some values from Vuex).

The component is using v-model=“selected” on a bunch of checkboxes. Then I have the following:

// Template
<grid-leaders
    v-if="selected.regions.length"
    v-model="selected"
/>

// Script
export default {
    data() {
        return {
            selectedProxy: {
                regions: [],
                parties: [],
            },
        }
    },
    computed: {
        selected: {
            get() {
                return this.selectedProxy
            },
            set(newVal) {
                this.selectedProxy = newVal

                // If I remove this next line, it works fine.
                this.$store.commit("SET_LEADER_REGIONS", newVal)
            },
        },
    },
    mounted() {
        // Restore saved selections if coming back from a specific page
        if (this.$store.state.referrer.name == "leaders-detail") {
            this.selectedProxy = {...this.$store.state.leaderRegions }
        }
    }
}

// Store mutation
SET_LEADER_REGIONS(state, object) {
    state.leaderRegions = object
}
1

1 Answers

1
votes

OK I figured it out! The checkbox component (which I didn't write) was doing this:

        updateRegion(region) {
            const index = this.value.regions.indexOf(region)

            if (index == -1) {
                this.value.regions.push(region)
            } else {
                this.value.regions.splice(index, 1)
            }

            this.$emit("input", this.value)
        },

The line this.value.regions.push(region) is the problem. You can't edit the this.value prop directly. I made it this:

        updateRegion(region) {
            const index = this.value.regions.indexOf(region)
            let regions = [...this.value.regions]

            if (index == -1) {
                regions.push(region)
            } else {
                regions.splice(index, 1)
            }

            this.$emit("input", {
                ...this.value,
                regions,
            })
        },

And then I needed this for my computed selected:

        selected: {
            get() {
                return this.selectedProxy
            },
            set(newVal) {
                // Important to spread here to avoid Vuex mutation errors
                this.selectedProxy = { ...newVal }
                this.$store.commit("SET_LEADER_REGIONS", { ...newVal })
            },
        },

And it works great now!

I think the issue is that you can't edit a v-model value directly, and also you also have to be aware of passing references to objects, and so the object spread operator is a real help.