vue-routerのナビゲーションガードを使う

はじめに

この記事は Treasure Advent Calender 2019 16日目の記事です。 大幅に遅刻(2回目)して大変申し訳ありません。

adventar.org

今回は、12/24 のクリスマスイブに行った、未来大 x 会津大 対バンLT会 で扱ったネタを書いていこうと思います。

speakerdeck.com

はじめていきます。

今回簡単なテストアプリのリポジトリはこちらです。

github.com

やりたいこと

認証が必要なAPIを使用している際、 session token が切れていた時に、/login に飛ばしたい。

アプリ構成としては以下な感じです。

f:id:tjmschk:20191228000535p:plain
architecture

各PageComponentのcreatedで、vuexのactionをdispatchし結果をstateにcommit、 Pageの生成時にstateの値を参照するという流れです。 今回はコンポーネントgreet: の後の文章を非同期で生成しています。

とりあえずtokenが有効かどうかを調べる isValidToken APIを生やしてもらいました。

solution1

方法

App.vue の created で、isValidToken を呼び、無効だったら /login に飛ばす。

結果

目的だった tokenが無効なら /login に飛ばす という処理はできたのですが、isValidToken 関数が非同期通信をしているため、tokenが無効というのが返ってきてから/login へ飛ばす処理の前にComponentのインスタンスが作られ、createdで呼んでいたAPIでのエラーが表示されていました。

Image from Gyazo

図としては以下の感じ。

f:id:tjmschk:20191228185437p:plain

solution2

方法

vue-routerの グローバルビフォーガード を使う。

グローバルビフォーガードとは

いつナビゲーションがトリガーされようとも、グローバル before ガードは作られた順番で呼び出されます。ガードは非同期に解決されるかもしれません。そしてそのナビゲーションは全てのフックが解決されるまで 未解決状態 として扱われます。

全てのフックが解決されるまで未解決状態として扱われます つまり非同期に解決されたとしてもインスタンスが作られず /login に飛ばせます。

ただし、この場合ナビゲーションがトリガー毎にリクエストを飛ばすのでパフォーマンス重視のアプリならやらない方がいいのかもしません。

追加したコード
const router = new VueRouter({
  routes
});

router.beforeEach((to, from, next) => {
  if (!store.state.isLoggedIn && to.path != '/login') {
    next('/login');
  }
  next();
});

※ 最初っからこっち使えよってわかるんですが↑の時は知りませんでした。無知の知

結果

Image from Gyazo

うまくいきました〜

おわりに

vue-routerのナビゲーションガードを使った場合、APIでの認証系エラーを表示せずログイン画面に遷移することができるようになりました。 しかし、ブログの途中でも言及しましたがこの方法だと画面遷移毎にリクエストを飛ばす必要があるためパフォーマンスを考えるとそんなよくなかったりするかも?

もしもっといい方法があったら教えてもらえると嬉しいです 🙇‍♀️

そしてTreasure2019のみなさん、アドカレ超遅刻してしまい申し訳ありませんでした。 迷惑かけた人には土下座するのでTreasureN次回誘ってください。