如何将Vuex中的大数据与Vue表单绑定,避免非法变更store状态报错
报错根因
你触发报错的核心原因是 Object.assign 属于浅拷贝,仅能复制form对象的第一层属性,你表单中address、children这类嵌套对象的引用仍然指向Vuex store中的原始state对象,修改表单嵌套属性时相当于直接修改了Vuex state,触发了Vuex严格模式的校验规则,才会抛出错误:
[vuex] Do not mutate vuex store state outside mutation handlers.
解决方案
根据你的业务场景可选择以下两种方案,均不需要为上百个字段单独定义计算属性:
方案1:表单修改不需要实时同步到Vuex(仅提交时更新store)
这是大多数表单场景的选择,你只需要对从store取到的表单数据做深拷贝,彻底切断本地form和store state的引用关联即可:
- 修改watch中对本地form的赋值逻辑,深拷贝的实现可选以下两种方式:
- 如果表单数据没有函数、Symbol、循环引用等特殊结构,可直接用原生方法实现:
handler(newVal) { this.form = JSON.parse(JSON.stringify(newVal)) } - 如果表单结构复杂,推荐用成熟的深拷贝实现(比如lodash的
cloneDeep方法):import { cloneDeep } from 'lodash' // ... handler(newVal) { this.form = cloneDeep(newVal) }
- 如果表单数据没有函数、Symbol、循环引用等特殊结构,可直接用原生方法实现:
- 后续表单提交时,再调用你已定义的
setFormmutation,将完整的本地form对象批量更新到store即可。
方案2:需要实时把表单改动同步到Vuex
如果你需要表单每一次修改都实时更新到store,可通过通用mutation+路径寻址的方式实现,不需要单独定义每个字段的计算属性:
- 先在Vuex的mutations中新增一个通用的字段更新方法:
mutations: { setForm(state, payload) { state.form = payload; }, // 新增通用更新方法 updateFormField(state, { fieldPath, value }) { // 按字段路径给state.form赋值 const pathArr = fieldPath.split('.') let target = state.form for (let i = 0; i < pathArr.length - 1; i++) { target = target[pathArr[i]] } target[pathArr[pathArr.length - 1]] = value } } - 修改组件的表单绑定逻辑,拆分v-model为属性绑定和事件监听:
<v-text-field :value="getFormFromStore.name" @input="updateField('name', $event)" /> <v-text-field :value="getFormFromStore.address.street" @input="updateField('address.street', $event)" /> <!-- 其余字段按照同样规则绑定即可 --> - 组件中新增通用更新方法:
methods: { ...mapActions('form', 'getForm'), updateField(fieldPath, value) { this.$store.commit('form/updateFormField', { fieldPath, value }) } }
这种方案仅需写一次通用逻辑,后续新增表单字段只需要按照规则绑定路径即可,适配大量字段的场景。
内容的提问来源于stack exchange,提问作者tryToFrontEnd
相关产品推荐
相关产品推荐

