由於遇到了一些 Google reCAPTCHA 的狀況,所以剛好找時間來重新檢視一下 Vue 元件的生命週期這件事。其實也不是 Vue 本身的問題,但是很奇妙的是,我真的就是遇到這種狀況。
剛好複習一下也好。
Lifecycle
首先還是先複習一下官方這張說明圖片,
接著回想一下我上次寫過,關於 Vue-Router 外面的那些事情。
然後我們來玩一下排列組合,在這邊只關注 剛進去 元件或是路由的情況,
beforeRouteEnter
beforeCreate
created
beforeMount
mounted
再加上,原先 beforeRouteEnter
當中有 next()
可以使用,所以你會有這種用法,
beforeRouteEnter (to, from, next) {
next(vm => {
// 我們在這邊也算他是 Lifecycle 的一環
// 先簡稱他叫做 nextInVM
})
}
所以我們先假設他叫做 nextInVM
好了,那麼,這些東西實際的執行順序會是什麼呢?
beforeRouteEnter
beforeCreate
created
beforeMount
mounted
nextInVM
元件內的執行順序
只有單一元件的時候,執行結果確實會向上述那樣。假設,你包含了其他元件,舉例來說,
App
- AComponent
- BComponent
- CComponent
- DComponent
那麼順序會是如何呢?首先,要先看你的 HTML 標籤順序 ,他會先決定元件的載入順序(大多數情況來說會依照此順序),如果上述的元件是這樣,
<app>
<a-component></a-component>
<b-component>
<c-component></c-component>
<d-component></d-component>
</b-component>
</app>
那麼你覺得在上述的載入執行順序會是如何?
beforeRouteEnter
從 App 發出beforeCreate
從 App 發出created
從 App 發出beforeMount
從 App 發出beforeCreate
從 A Component 發出created
從 A Component 發出beforeMount
從 A Component 發出beforeCreate
從 B Component 發出created
從 B Component 發出beforeMount
從 B Component 發出beforeCreate
從 C Component 發出created
從 C Component 發出beforeMount
從 C Component 發出beforeCreate
從 D Component 發出created
從 D Component 發出beforeMount
從 D Component 發出mounted
從 A Component 發出mounted
從 C Component 發出mounted
從 D Component 發出mounted
從 B Component 發出mounted
從 App 發出nextInVM
從 App 發出
還記得 beforeRouteEnter
這個東西,沒有在 Router 裡面不會觸發吧?所以 nextInVM
這件事情只會存在於 App 裡面而已。
雷點
有些外掛套件,或是有時候我們想自己注入一點其他的東西,那麼注入的 時機點 就變得異常的敏感。如果以為 created
或是 mounted
都是萬解的話,請看一下上面提到的順序,如果 D Component 要用的東西,由 B Component 去載入,即便順序提前,他還是有機會找不到東西的。
所以諸如 Google reCAPTCHA 的 API,他還是建議你寫在 index.html
裡面,像我自己動態載入就會出現 reCAPTCHA API 找不到的情況。
爾或者是,當你注入的東西是屬於非同步傳輸,那麼就更有機會找不到當初注入的東西。所以,有這一些相關的注入,可能還是得使用 Events 或是在外面做一個 EventBus 來解決,起碼有個 onLoad
事件能夠讓你知道注入的東西已經讀取完畢。
接著,next()
會讓人覺得是路由進入之後,第一個會跑的東西,但是,請回頭看一下上述的順序。
天殺的他是最後才執行!
所以,有些運算的資料邏輯,放在這裡面,是有機會造成其他子元件的異常的。如果有搭配好 Vuex 或許可以解決部分狀況,不過,還是建議兒子的事情交由兒子自己去做,不要逢年過節就問什麼時候要生孩子之類的問題。
至於我踩到的雷點,是因為外掛用了 defer()
,他先註冊一個 defer()
來等待 Google reCAPTCHA 載入成功,之後再去初始化。問題來了,如果我將 Google reCAPTCHA 的 API 動態載入,那麼,思考一下這個狀況,
- 到底是 reCAPTCHA API 先載入?
- 還是外掛先掛入
defer()
來等待resolve
? - 當中會判斷
window.hasOwnProperty('grecaptcha')
是否為真
理論上來說,應該是,
- 先掛入
defer()
來等resolve
- 載入 Google reCAPTCHA API 使用
onload
參數回戳外掛初始化 - 外掛收到 API 回呼後
resolve
- 啟動 Google reCAPTCHA 功能
然後,
我起不來!
然後套件的
defer()
是錯的!
但是我懶得吐嘈了。
小結
套件還是自己寫比較靠譜,重造輪子偶爾還是有點用處的(選我正解。