我有一个视图,它是个人资料页面,可帮助用户更新其个人资料信息。我最初使用以下方法从商店中提取数据:
this.$store.state.auth.user
但是,当我使用v-model
将其绑定到输入控件时,<input>
更改了input
事件的Vuex状态属性。根据文档中的解决方案,我更改了控件以使用:value
属性显示其内容,并使用Object.assign()
将状态数据合并到本地属性中:
user: Object.assign({
name: ''
...
}, this.$store.state.auth.user),
这部分起作用,因为现在保存数据后,看来合并对象中的数据正在引用状态对象,因此,如果用户在销毁组件之前尝试再次更新数据,则会得到:
"Error: [vuex] do not mutate vuex store state outside mutation handlers."
我意识到提交后我可能可以重新初始化本地属性,并且我可以始终运行:
this.$router.go()
但是我有种na的感觉,我犯了一个男生错误。解决此问题的惯用方法是什么?
答案 0 :(得分:0)
Object.assign
仅创建一个shallow copy,因此您的user
副本仍将引用原始user
对象的任何嵌套对象值,如下面的演示所示:
const orig = {
age: 21,
name: {
first: 'John',
last: 'Doe'
},
username: 'jdoe_11',
}
const copy = Object.assign({}, orig) // or: const copy = { ...orig }
// both `name` properties refer to the *same* nested object
console.log('copy.name === orig.name =>', copy.name === orig.name) // => true
copy.name.first = 'Bob'
console.log('orig.name.first =>', orig.name.first) // => 'Bob'
如果要制作与原始对象隔离的深层副本,建议使用lodash.cloneDeep
之类的实用工具,该实用工具以递归方式复制对象,包括所有嵌套属性:
const orig = {
age: 21,
name: {
first: 'John',
last: 'Doe'
},
username: 'jdoe_11',
}
const copy = _.cloneDeep(orig)
console.log('copy.name === orig.name =>', copy.name === orig.name) // => false
copy.name.first = 'Bob'
console.log('orig.name.first =>', orig.name.first) // => 'John'
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.min.js"></script>
Vuex docs讨论了您的方案的解决方案。
处理它的“ Vuex方法”是绑定
<input>
的值,并在input
或change
事件上调用操作:<input :value="message" @input="updateMessage">
// ... computed: { ...mapState({ message: state => state.obj.message }) }, methods: { updateMessage (e) { this.$store.commit('updateMessage', e.target.value) } }
这是变异处理程序:
// ... mutations: { updateMessage (state, message) { state.obj.message = message } }
双向计算属性
诚然,上面的内容比
v-model
+局部状态要冗长得多,并且我们也失去了v-model
的一些有用功能。一种替代方法是使用带有setter的双向计算属性:<input v-model="message">
// ... computed: { message: { get () { return this.$store.state.obj.message }, set (value) { this.$store.commit('updateMessage', value) } } }
如果上面推荐的解决方案不可行,您可以最后禁用Vuex的strict mode。请注意,严格模式是一种开发工具,可以防止突变处理程序之外的意外状态更改,因此在禁用它时应格外小心:
// store.js
export default new Vuex.Store({
// ...
strict: false // ? disable strict mode
})