Vue Router v4 のナビゲーションガード：種類と使い方

# はじめに
編集中に画面遷移をしようとしたときに、「編集中の内容があるが保存せずに移動していいか」を確認するモーダルを出したいという場面に遭遇し、Vue Routerのナビゲーションガードを使用しました。

実装を進めるなかで、Vue Routerのナビゲーションガードの種類、それぞれの使用法を学んだのでまとめます。

# ナビゲーションガードとは

Vue Routerのナビゲーションガードは、ルートの遷移前後の処理を制御できる仕組みです。
主に、リダイレクト（別ページに強制移動）やキャンセル（ページ遷移を中断し、現在のページにとどまる）によってルートの遷移を防ぐために使用されます。


:::note warn
Vue Router のナビゲーションガードはVue Routerの仕組みであるため、Vue Router を通じたルート遷移でのみ発火します。
そのため、\<a>タグを直接用いた場合、通常のHTMLナビゲーションとして処理され、Vue Router のガードが適用されません。
Vue Router のガードを機能させるには、\<router-link> や router.push() を使用する必要があります。
:::
# ナビゲーションガードの種類
 Vue Routerには以下3種類のナビゲーションガードがあります。

 1. グローバルガード
 2. ルート単位ガード
 3. コンポーネント内ガード 

それぞれについて説明します。

## グローバルガード
グローバルガードはアプリ全体のルート遷移に対して適用されるガードです。
3種類あり、それぞれ実行されるタイミングが異なります。

- `beforeEach`：ルート遷移前に実行
- `beforeResolve`：すべてのコンポーネント内ガードと非同期のコンポーネント読み込み終了後に実行
- `afterEach`：ルート遷移完了後に実行

```javascript
const router = createRouter({ ... })

router.beforeEach((to, from) => {
  // ...
  // falseを返すことでナビゲーションをキャンセルできる
  return false
})
```

それぞれのガード関数は、以下2つの引数を受け取ります。
どちらもルートオブジェクトです。
- `to`：遷移先のルート情報
- `from`：現在のルート情報


以下の戻り値を設定できます。
- `false`：ナビゲーション（ルート遷移）をキャンセルする
- `ルートロケーションオブジェクト`：現在のナビゲーションをキャンセルし、router.push() のように新しいルートへの遷移を開始

```javascript
router.beforeEach((to, from) => {
  if (!isAuthenticated && to.name !== 'Login') {
    return { name: 'Login' } // ログインページへリダイレクト
  }
})
```

:::note info
第3引数 next について
Vue Routerの以前のバージョン(v3)では、nextという第3引数が用いられていましたが、v4では推奨されていません。しかし、現在も使用可能となっています。
nextを使用する書き方は、以下の公式ガイドを参照してください。
:::

https://v3.router.vuejs.org/ja/guide/advanced/navigation-guards.html#%E3%82%AF%E3%82%99%E3%83%AD%E3%83%BC%E3%83%8F%E3%82%99%E3%83%AB%E3%83%92%E3%82%99%E3%83%95%E3%82%A9%E3%83%BC%E3%82%AB%E3%82%99%E3%83%BC%E3%83%88%E3%82%99

## ルート単位ガード
ルート単位ガードは、グローバルガード (beforeEach)とは異なり、**特定のルート** に対して設定するガードです。
- `beforeEnter`：特定のルート設定内で直接定義すると、そのルートに新しく入るときのみ実行される。
ただし、同じルートで params だけが変更される場合（例: /users/1 → /users/2）は発火しない。

以下の例では、ユーザーが /users/1 や /users/2 などにアクセスしようとするとナビゲーションがキャンセルされます。

```javascript
const routes = [
  {
    path: '/users/:id', // 例： /users/1、　/users/2　など
    component: UserDetails,
    beforeEnter: (to, from) => {
      // ナビゲーションをキャンセル
      return false
    },
  },
]
```

## コンポーネント内ガード
コンポーネント内ガードは、各コンポーネント内で定義するガードです。
特定のコンポーネントが表示・更新・削除されるときに処理を実行することができます。
コンポーネント内ガードは以下の3種類あります。

- `beforeRouteEnter`：
コンポーネントが表示される前に実行
コンポーネントが作成される前なので、this（コンポーネントのインスタンス）にはアクセスできない
- `beforeRouteUpdate`：
コンポーネントが再利用されるとき（同じコンポーネントが使われたまま、URL のパラメータが変わったとき）に実行
例： /users/1 → /users/2 への遷移
- `beforeRouteLeave`：
コンポーネントから離れる前（異なるページに遷移するとき）に実行
ページを離れる前に確認メッセージを出すときに使用される

```vuejs
<script>
export default {
  beforeRouteEnter(to, from) {
    //...
  },
  beforeRouteUpdate(to, from) {
    //...
  },
  beforeRouteLeave(to, from) {
    //...
  }
}
</script>
```

上記はOptionsAPIの書き方です。
Composition APIの場合は、以下を参照してください。

https://router.vuejs.org/guide/advanced/composition-api.html#Navigation-Guards

# 最後に
「編集中の内容があるが保存せずに移動していいか」を確認するモーダルを出したかったので、今回は `beforeRouteLeave`のみを使用しましたが、これを機に初めてナビゲーションガードを学習することができました。

公式のドキュメントは英語で書かれていたり、難しかったりして避けてしまいがちでしたが、最新の情報を得るためには、公式ガイドを活用することが重要だと実感しました。


最後までお読みいただきありがとうございました！

# 参考

https://v3.router.vuejs.org/ja/guide/advanced/navigation-guards.html#%E3%83%8A%E3%83%92%E3%82%99%E3%82%B1%E3%82%99%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%82%AB%E3%82%99%E3%83%BC%E3%83%88%E3%82%99

https://router.vuejs.org/guide/advanced/navigation-guards.html