2017-09-23 54 views
4

我有一個用例,我可能需要將一個對象props作爲道具傳遞給子組件。Vue2中的條件道具

最初,我有一個組件中包含的表單和表。該表單將接受輸入,將執行一個異步請求,併爲該用戶提供該表以供選擇。然後用戶可以按下一個按鈕並隱藏表格,並將表格帶回來,以便重新輸入參數。由於表單的內容取決於其父項的狀態,因此最後的搜索參數仍處於表單中。

當我重構組件以創建父窗體和表的子組件時,就會出現此問題。現在表單將$emit事件發送給它的父項,它將執行異步操作並將結果作爲props傳遞給表。這工作得很好,但是當用戶點擊「返回到表單」按鈕時,表單被重新呈現,從而將其狀態重置爲初始值。

我試圖將表單的內容存儲在父級中,並將其傳回到表單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

然後我用三元初始化與道具的值或空字符串數據對象試過了,是這樣的:

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未在該實例定義,但在渲染過程中被引用。我猜這意味着使用三元來初始化道具是錯誤的。

然後我試圖在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的方式來實現這一目標嗎?

回答

0

我認爲你應該能夠通過將FormComponent中的代碼從數據移動到計算來進行排序。
計算屬性是反應性的,所以當initialValues prop最終獲得一些數據時,表單應該反映它。
如果initialValues始終具有address1,address2等結構(即使它們最初爲null),Object.assign也會起作用。如果不是(即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> 

爲了保持表格值下一輪需要通過發光以通過selectedAddress起來,並將其應用父類型值

我非常喜歡的一種替代方法是Vuex,表單從商店獲取初始值並通過一個操作發佈回商店,該操作啓動異步工作並使用結果更新商店。本質上你的displayResults方法變成了動作,但你並不需要async..a等待。

Vuex正式將數據流模式,以便您可以更輕鬆地推理和調試。本質上,你不必擔心將數據傳遞給道具並通過散發。

又一想,你能避免使用V-秀,而不是V-如果FormContainer重置FormComponent值。這應該保留形式div(和它的狀態),但隱藏它。然後,您可能不需要在父項上擁有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> 
+0

我目前使用的是Vuex,我實現的解決方法是使用Vuex。我的問題是,我必須確保記得在所有適當的時間,即當表單容器的父級從DOM中刪除時,當用戶重置表單時,記錄分派正確的操作以從商店中刪除數據從表單中,當用戶從其父母等重置表單時,我可以看到這是一種簡單的方法,在表單中有一個不正確的初始狀態。 – JavaTheNutt

+0

使用計算屬性並不意味着如果在表單仍處於打開狀態時,「initalValues」的內容發生了變化,那麼表單字段值本身會發生變化?我試圖使用Object.assign()來打破錶單值和從父類傳遞的數據之間的鏈接,如果它在'computed(){}'中使用,情況仍然如此嗎? – JavaTheNutt

+0

我確實喜歡隱藏表單的想法,它會降低複雜性,並且它不是掛在DOM周圍的一個巨大組件。我知道通常會接受的做法是移除未使用的元素,而不是隱藏它們,但在這種情況下,我可能會做出豁免 – JavaTheNutt