vue-routerにはonReady
というフックが用意されている。
ドキュメントを読めばわかるように、これは when the router has completed the initial navigation, which means it has resolved all async enter hooks and async components that are associated with the initial route.
、つまり最初に表示するルートに紐付けられたbeforeEnter
ナビゲーションガードやbeforeEach
globalナビゲーションガードが解決され、「どのrouteが実行されるべきか」が解決されたあとに呼ばれる。
これが便利になるのはSSRのときで、preloadしたいデータがあるような場合はbeforeEnter
内で非同期読み込みし、その読み込みが終わったらnext
するようにしておき、onReady
のタイミングでSSRすればよい、というような使いかたができるわけだ。
ところで、ナビゲーションガードが解決されたあとに呼ばれるhookはもうひとつある。それがafterEach
グローバルhookだ。
このafterEach
というhookとonReady
hookはどちらが先に呼び出されるのだろう。ドキュメントを読んでもよくわからなかったので、ソースを追った。
まず、onReadyで登録したhookを実際に呼び出しているのはここである。
transitionTo (location: RawLocation, onComplete?: Function, onAbort?: Function) { const route = this.router.match(location, this.current) this.confirmTransition(route, () => { this.updateRoute(route) onComplete && onComplete(route) this.ensureURL() // fire ready cbs once if (!this.ready) { this.ready = true this.readyCbs.forEach(cb => { cb(route) }) // ココね!!!ここ!!! } }, err => { if (onAbort) { onAbort(err) } if (err && !this.ready) { this.ready = true this.readyErrorCbs.forEach(cb => { cb(err) }) } }) }
で、その前にコールされてるthis.updateRoute(route)
の中身見ると
updateRoute (route: Route) { const prev = this.current this.current = route this.cb && this.cb(route) this.router.afterHooks.forEach(hook => { hook && hook(route, prev) }) }
ここでafterHooksを呼んでいる。というわけで、onReady
よりも先にafterEatch
のhookが呼ばれるようになっていることが確認できた。
注意すべき点として、(あたりまえだが)afterEach
は同期的に呼び出されているので、その中で非同期な操作を行った場合、その非同期操作の完了を待たずにonReady
hookが呼び出されるので、onReady
にhookしてSSRしても、afterEach
内で行った非同期操作の結果はSSRされない。