2016-09-26 32 views
7

我有一個父/子組件設置,父母從服務器加載數據並通過道具傳遞給兒童。在這個孩子中,我想用父母收到的一些數據實例化一個jQuery日曆。VueJs子組件道具沒有立即更新

爲了在設置日曆之前等待數據,我在父項中廣播了一個事件,該事件中有一個爲子項設置的事件偵聽器。

監聽器正在被解僱,但如果我this.$log('theProp'),它是未定義的。但是,如果我用VueJs devtools檢查組件,那麼父母/孩子的關係就在那裏,同時這個孩子已經收到了道具。

道具在兒童身上被定義爲動態道具:the-prop="theProp"。由於孩子最終收到道具,我假設我的設置是正確的,但似乎有某種延遲。父母在ajax調用的返回函數中設置道具並且再次:它正在工作,只是稍微延遲了一下。

我還試着在兒童道具上註冊一個watch監聽器,這樣我就可以設置日曆,並確保道具在那裏。但是,監聽者會觸發,但this.$log('theProp')仍未定義。

如果我將數據與廣播電話一起傳遞,如this.$broadcast('dataLoaded', theData),孩子接收它就好了。但這樣做似乎是錯誤的,因爲我基本上構建了自己的道具處理程序。

我沒有發佈任何代碼,因爲組件相當大,VueJs devtools告訴我父/子情況正在工作。

我是否缺少一些信息?在設置父母的值和接受父母的孩子之間是否有輕微的延遲?等待孩子父母數據的正確方法是什麼?

通常,當您只是將數據呈現到模板中時,由於數據綁定到模板,時序並不重要。但在這種情況下,我確實需要數據來設置日曆,否則將會出錯。

謝謝。

編輯1:這裏是一個的jsfiddle:https://jsfiddle.net/dr3djo0u/1/ 這似乎證實,廣播後馬上數據不可用。然而,觀察者確實工作,儘管我幾乎可以發誓,當我設置測試用例時,有時this.$log('someData')返回undefined

但我想我的問題可能在別的地方,今晚我會看看,現在沒有和我在一起的項目。

編輯2:做了一些更多的測試。我的問題是a)事件監聽器似乎不能立即收到數據,並且b)我也試圖在route.data回調中初始化日曆,如果someData已經在(例如來自父代時),但是調用該路由回調組件準備就緒之前,所以它不在那裏工作。

我的解決方案現在是這樣的:

// works when the child route is loaded directly and parent finishes loading someData 
watch: { 
    someData() { 
     this.initCalendar(); 
    } 
}, 

// works when navigating from parent (data already loaded) 
ready() { 
    if (this.someData && this.someData.length) { 
     this.initCalendar() 
    } 
} 
+1

嗨,你可以提供一個簡單的代碼示例來重現該問題? – Nora

+2

如果你正在'監視'一個變量,並且'watch'內的值是未定義的,事實上它將它設置爲undefined。 –

+0

感謝您的意見。用我發現的問題更新了我的問題。 – Chris

回答

3

據我所知,你不應該需要事件從父數據傳遞給孩子。

所有你需要的是,在子組件:props: ['theProp']

而且在父母使用子組件時:<child :theProp="someData"></child>

現在,無論在你改變someData父,子組件會做出相應的反應。

你不需要事件,你不需要「看」,你不需要「準備好」。


例如:AJAX調用後,在父母的「準備就緒」,加載一些數據:

// at the parent component 

data: function() { 
    return { 
    someData: {} 
    } 
}, 

ready: function() { 
    var vm = this; 
    $.get(url, function(response) { 
    vm.someData = response; 
    }); 
} 

現在,你不需要任何其他的數據傳遞給孩子。它已經在theProp在小孩!

你真正需要做的是在孩子身上有什麼反應到自己的theProp屬性的數據變化。

無論是在界面:

<div v-if="theProp.id > 0"> 
    Loaded! 
</div> 

或者JavaScript代碼:

// at the child component 

computed: { 
    // using a computed property based on theProp's value 
    awesomeDate: function() { 
    if (!this.theProp || (this.theProp.length === 0)) { 
     return false; 
    } 
    if (!this.initialized) { 
     this.initCalendar(); 
    } 
    return this.theProp.someThing; 
    } 
} 

更新1

您也可以在父母,使孩子有條件地:

<child v-if="dataLoaded" :theProp="someData"></child> 

只有當數據可用時纔將dataLoaded設置爲true。

更新2

或者,也許你的問題涉及到change detection caveat

也許你在創建對象的新屬性...

vm.someObject.someProperty = someValue 

...當你應該做...

vm.$set('someObject.someProperty', someValue) 

...等「注意事項」。

更新3

在VueJS 2,你不侷限於模板。您可以使用render function並編寫您想要的最複雜的渲染邏輯。

更新4(關於OP的編輯2

也許你可以刪除ready和使用immediate選項,這樣你的初始化是在同一個地方:

watch: { 
    someData: { 
    handler: function (someData) { 
     // check someData and eventually call 
     this.initCalendar(); 
    }, 
    immediate: true 
    } 
} 
+0

我通過道具傳遞數據,我的問題是關於對接收數據更改作出反應,因爲我必須根據它進行初始化。計算屬性不是去爲那種事情imho的方式。 – Chris

+0

我已經更新了我的答案,包括其他建議。然而,imho計算的屬性對於這種情況非常合適。您可以基於'someData'創建'isReady'或'isLoaded'計算屬性。事實上,如果你需要對數據變化做出反應,計算出來的屬性**就是要走的路。 –

+0

使用模板時,是的。在一個方法中,如果我檢查'if(this.isLoaded)'並且當時沒有加載,我想我有機會實例化日曆。因此,我必須觀察數據以獲得第二次更新中所述的更改。效果很好。 – Chris