So I'm getting the following error message:
[Vuex] Do not mutate vuex store state outside mutation handlers.
The reason behind this error according to the Vuex docs is because the following code tries to directly mutate the state.
<template>
<div v-for="item in basicInformation" :key="item.id">
<el-col :span="12">
<el-form-item label="First Name">
<el-input v-model="item.firstName" />
</el-form-item>
</el-col>
</div>
</template>
export default {
computed: {
...mapState(['teststore']),
basicInformation: {
get() {
return this.teststore.personData.basicInformation
},
set(value) {
this.$store.commit('updateBasic', value)
}
}
}
}
I get why Vuex is throwing that error, since I am still trying to directly mutate the state. So a solution for this particular problem according to the docs would be using a two-way computed property with a setter (like in the example above), and that works fine for a single inputfield. However, I have A LOT of inputfields for the user to fill in. Consider the following code:
personData: {
basicInformation: [
{
firstName: '',
surname: '',
email: '',
phone: '',
street: '',
city: '',
position: '',
website: '',
}
],
}
Creating a two-way computed property with a setter for all my inputfields seems very verbose. Is there an easy way where I can use Vuex and preferably v-model
with an array of objects to create inputfields?
You can create a copy of basicInformation
to have this inside component scope.
So associate a computed property to basicInformation
and use it in v-models should kill this warning.
<template>
<div v-for="item in localBasicInformation" :key="item.id">
<el-col :span="12">
<el-form-item label="First Name">
<el-input v-model="item.firstName" />
</el-form-item>
</el-col>
</div>
</template>
<script>
computed: {
localBasicInformation() {
return [...this.basicInformation];
},
},
</script>
Just pay attemption about the differences between shallow and deep copy. If this.localBasicInformation
is deep, spread operator will not work and you will need something like cloneDeep from lodash.
I would do something like this:
Codesandbox: https://codesandbox.io/s/vuex-store-ibjbr
<template>
<div>
<div v-for="(value, key) in basicInformation" :key="key">
<el-col :span="12">
<el-form-item :label="keyToLabel(key)">
<el-input :value="value" @input="onInput({ key, value: $event })" />
</el-form-item>
</el-col>
</div>
</div>
</template>
<script>
export default {
computed: {
...mapState(['teststore']),
basicInformation() {
return this.teststore.personData.basicInformation
},
},
methods: {
onInput({ key, value }) {
this.$store.commit('updateBasic', { key, value })
},
keyToLabel(key) {
// This is only an example
const keyToLabel = {
firstName: 'First Name',
// And so on...
}
return keyToLabel[key]
},
},
}
// And in your store, something like this
const store = {
// ...
mutations: {
updateBasic(state, { key, value }) {
state.teststore.basicInformation[key] = value
},
},
}
</script>
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.