SPA のサイトは、トップページ(index.html)を JavaScript によって DOM を書き換えることで成り立っており、コンポーネントの描画後 Ajax でデータを取得してそれに応じたテキストを表示しています。
ただこの場合データを取得している間は必ずローディングが発生します。
Vue
ではcreated
やmounted
などのライフサイクルフックでデータ呼び出しを行いますが、Vue
Router
を使った場合はコンポーネントの生成前(ページ遷移を行う前に)にデータを取得する事ができます。
たとえば、トップページからユーザ一覧のページに遷移する場合、以下のように書くことができます。
export default {
data() {
return {
users: []
}
}
async beforeRouteEnter(to, from, next) {
const res = await axios.get('/api/users');
if (200 !== res.status) {
return;
}
next(vm => vm.users = res.data)
},
async beforeRouteUpdate(to, from, next) {
const full_path = to.full_path;
const res = await axios.get(`/api${full_path}`);
if (200 !== res.status) {
return;
}
this.users = res.data;
next();
},
};
この時、beforeRouteEnter
が発火し、画面遷移を行う前にデータを取得します。
成功すれば画面遷移を行い、エラーの場合はトップページのまま移動しません。
beforeRouteUpdate
は同一ページ内でコンポーネントを再利用する場合(クエリーをつけて検索結果を返す、またはページネーションをするとき)に発火します。
気をつけなければならないのはbeforeRouteEnter
ではthis
が使えないということです。
通常 Vue
ではコンポーネントが生成されてから呼び出しを行うのですが、生成前なのでthis
が使えません。その代わりnext()
に含まれているので遷移時にデータを渡すことになります。
本来の目的は動的に取得されるデータを参照して、vue-headやvue-hackernews-2.0などの方法を使って、ページのタイトルを付けることだったのですが、遷移前にデータを取得しても上手く反映されませんでした。
データが揃ってからページを表示するという、UX 的には良い変更になったのですが本来の目的が達成できていないので思案中です。