我有一个用例,在这个用例中,我可能需要将对象props作为道具传递给子组件。
最初,我在一个组件中包含了一个表单和一个表。此表单将接受输入,将执行异步请求,并将呈现表格以供用户进行选择。然后,用户可以点击一个按钮,将表格隐藏起来,并重新显示表单,以便重新输入参数。由于表单的内容依赖于其父表单的状态,因此最后的搜索参数仍在表单中。
当我重构组件以使表单和表都成为父组件的子组件时,问题就出现了。现在,表单将把事件$emit到其父对象,父对象将执行异步操作,并将结果作为props传递给表。这可以很好地工作,但是当用户点击"return to form“按钮时,表单将被重新呈现,从而将其状态重置为初始值。
我尝试将表单的内容存储在父表单中,并将其作为props传递回表单,但这导致了初始值设置的问题。我不想直接改变道具,所以我尝试了这种方法:
FormContainer.vue
<template>
<div v-if="formShown">
<form-component :initialValues="formValues" @formSubmitted="displayResults"></form-component>
</div>
<div v-if="tableShown">
<table-component :results="fetchedResults" @returnToForm="returnToForm"></table-component>
</div>
</template>
<script>
export default {
data(){
return{
formShown: true,
tableShown: false,
formValues:{
address1: '',
address2: '',
address3: '',
country: ''
},
fetchedResults: []
}
},
methods:{
async displayResults(){
this.fetchedResults = await someAsynchronousCall();
this.formShown = false;
this.tableShown = true;
},
returnToForm(){
this.tableShown = false;
this.formShown = true;
}
}
}
</script>FormComponent.vue
<template>
<!--Some form fields here, bound to data(){}, ommitted for brevity-->
</template>
<script>
export default{
props:['initialValues'],
data(){
return{
//Original structure
/*selectedAddress:{
address1: '',
address2: '',
address3: '',
country: ''
}*/
selectedAddress: JSON.parse(JSON.stringify(this.initialValues)) //Object.assign({}, this.initialValues) //tried both of these for deep copy
}
}
}
</script>这样做的问题是,在最初创建组件时,会向它传递一个空对象(或者更确切地说,是一个只有空属性的对象,我假设它们的数量是一样的),这意味着我的数据属性被初始化为undefined。
然后,我尝试使用一个三元组来使用props中的值或一个空字符串来初始化数据对象,如下所示:
data(){
return{
selectedAddress: {
address1: this.initialValues.address1 ? this.initialValues.address1 :'',
address2: this.initialValues.address2 ? this.initialValues.address2 :'',
address3: this.initialValues.address3 ? this.initialValues.address3 :'',
country:this.initialValues.country ? this.initialValues.country :''
}
}
},但这会抛出错误,指出selectedAddress未在实例上定义,但在呈现过程中被引用。我猜这意味着使用三元组来初始化props是错误的。
然后,我尝试检查mounted(){}生命周期钩子中的属性,并在那里设置数据属性,如下所示:
mounted(){
if(!this.initialValues || _.isEmpty(this.initialValues)){
Logger.info(`no props passed, no setup needed`);
return;
}
if(this.initalValues.address1){
Logger.info(`setting address 1`);
this.selectedAddress.address1 = this.initalValues.address1;
}
if(this.initialValues.address2){
Logger.info(`setting address 2`);
this.selectedAddress.address2 = this.initalValues.address2;
}
if(this.initialValues.address3){
Logger.info(`setting address 3`);
this.selectedAddress.address3 = this.initalValues.address2;
}
if(this.initialValues.country){
Logger.info(`setting country`);
this.selectedAddress.country = this.initalValues.country;
}
}这适用于表单的第一次运行,但在挂载组件时,this.initialValues始终为undefined。我检查了组件状态,发现initialValues确实存在,只是不在mounted生命周期挂钩期间。不管怎么说,这种方法让人感觉很“老土”。
我真的不知道下一步该怎么做。如果表单被重新挂载,我可以将表单数据提交到存储区并再次获取它,但我不认为提交应该仅在其父级被挂载时才存在的东西是正确的方法。
有谁能指导我用更Vue的方式来实现这一点吗?
发布于 2017-09-23 16:59:14
我认为您应该能够通过将FormComponent中的代码从数据转换到计算来解决这个问题。
计算属性是反应性的,所以当initialValues属性最终获得一些数据时,表单应该会反映出来。
如果Object.assign始终具有address1、address2等结构(即使它们最初为空),则initialValues将工作。如果不是(即initialValues初始= {} ),则必须逐个进行属性检查。
<template>
<!--Some form fields here, bound to data(){}, ommitted for brevity-->
<div>selectedAddress.address1</div>
<div>selectedAddress.address2</div>
</template>
<script>
export default{
props:['initialValues'],
data(){
},
computed: {
selectedAddress() {
return Object.assign({}, this.initialValues)
}
}
}
</script>为了在下一轮中保留表单值,您需要通过emit向上传递selectedAddress,并将它们应用于父formValues。
我非常喜欢的另一种方法是Vuex,表单从存储中获取初始值,并通过操作回发到存储中,该操作启动异步工作并使用结果更新存储。从本质上讲,你的displayResults方法变成了动作,但是你不需要async..await。
Vuex将数据流模式正式化,因此您可以更轻松地推断和调试。从本质上讲,您不必担心通过emits将数据传递给prop和out。
在另一种思想中,您可以通过在FormContainer中使用v- FormComponent而不是v-if来避免重置show的值。这应该保留表单div (以及它的状态),但将其隐藏。然后,您可能根本不需要在parent上安装formValues。
<template>
<div v-show="formShown">
<form-component :initialValues="formValues" @formSubmitted="displayResults"></form-component>
</div>
<div v-show="tableShown">
<table-component :results="fetchedResults" @returnToForm="returnToForm"></table-component>
</div>
</template>https://stackoverflow.com/questions/46377169
复制相似问题