我使用next2.15.3
在我的应用中,用户可以设置他们的客户可以回答的问题,这些问题可以是各种类型的,其中一个是多项选择题。这些类型的问题都有一个标题,以及可供人们选择的多个答案选项。
在我的问题页面上,我列出了所有用户的问题,我想允许他们编辑任何问题,但是我在弄清楚如何做到这一点时遇到了一些麻烦,至少在编辑多项选择题时。就目前而言,我有一个EditQuestion
组件,我从我的QuestionCard
组件传递一个question
道具,该道具只是存储在Vuex中的问题的细节。
EditQuestion
组件的当前(简化为SO)版本:
<template>
<input v-model="questionTitle" type="text">
<div v-if="question.type === 'multiple_choice'">
<input v-for="option in questionOptions" v-model="option.content" type="text">
</div>
<button @click.prevent="updateQuestion"></button>
</template>
<script>
export default {
props: {
question: {}
},
data() {
return {
questionTitle: this.question.title,
questionOptions: this.question.options
}
},
methods: {
updateQuestion() {
// Call the API with the new question details
}
}
}
</script>
如果我只编辑题目,这很有效。然而,我的问题来自于选项。如果我尝试更新一个,Vuex警告我关于突变之外的存储状态的突变,它警告我,即使我克隆question.options
,例如通过做questionOptions: Object.assign({}, this.question.options)
或questionOptions: {...this.question.options}.
,让我困惑的部分是为什么Vuex不抱怨当我修改questionTitle
数据对象时,只有在编辑问题选项?
参考如果它是相关的,question.title
只是一个简单的字符串,而question.options
是一个对象,看起来像这样:
{
"0": {
"id": 0,
"content": "Option 1"
},
"1": {
"id": 1,
"content": "Option 2"
}
}
对我来说,允许人们编辑选择题选项的最好方法是什么?
在JavaScript中,原语(String
,Number
,BigInt
,Boolean
,undefined
和null
)通过值复制,而对象(包括Array
,Map
,WeakMap
,Set
,WeakSet
)通过引用复制。
this.question.title
是String
,因此按值将其复制到新变量中。另一方面,this.question.options
是一个对象(它看起来像Array
),所以它通过引用复制到questionOptions
,因此questionOptions
和this.question.options
在Vuex中引用同一个对象。
克隆传入的this.question.options
的想法是正确的解决方案,但是Object.assign()
和扩展操作符只创建仍然引用相同原始对象的浅拷贝,这解释了当组件试图修改浅拷贝时Vuex状态突变警告。
export default {
data() {
return {
questionTitle: this.question.title,
questionOptions: JSON.parse(JSON.stringify(this.question.options))
}
}
}
演示尝试制作question
对象的本地副本,并仅在该本地副本上执行所有更新,如下所示:
<script>
export default {
props: {
question: {}
},
data() {
return {
localCopyOfQuestion: JSON.parse(JSON.stringify(this.question)),
questionTitle: this.localCopyOfQuestion.title,
questionOptions: this.localCopyOfquestion.options
}
},
methods: {
updateQuestion() {
// Call the API with the new question details
}
}
}
</script>