logo

Next15.3で追加された onNavigate でページ遷移をブロックする時のメリット・デメリット

2025-11-28
a month ago

開発環境

  • next: 16.0.3

前提

AppRouterを使用しています。

Next.js の Pages Router では、router.events を利用してページ遷移開始 (routeChangeStart) をフックし、その場でキャンセルすることが可能でした。

しかし App Router へ移行後、この仕組みは廃止され、同様のページ遷移ブロックはできなくなりました。

Next.js 15.3 では、新たに onNavigate が導入され、App Router でもページ遷移をブロックできる仕組みが追加されたので、本記事ではその使用感を整理します。

本題

Pages Router 時代のページ遷移キャンセル

あくまでイメージですが、Pages Router の router.events は次のように書くことで遷移キャンセルができていました。

router.events.on('routeChangeStart', (url) => {
  if (!confirm('ページを移動しますか?')) {
    router.events.emit('routeChangeError');
    throw 'Route change aborted.';
  }
});

App Router に移行するとこれが廃止となり、遷移そのものを止める方法がなくなっていました

Next.js 15.3 の onNavigate の登場

App Router の <Link> コンポーネントに onNavigate が新しく追加されました。

onNavigate はクライアント側のナビゲーション中にのみ呼ばれるコールバックです。

基本的な使い方

'use client'

import Link from 'next/link'

export default function Page() {
  return (
    <div>
      <Link
        href="/dashboard"
        onNavigate={(e) => {
          if (!window.confirm('未保存の変更があります。移動しますか?')) {
            e.preventDefault() // 遷移キャンセル
          }
        }}
      >
        ダッシュボードへ
      </Link>
    </div>
  )
}

confirm にしか頼れない理由(仕様上の注意)

onNavigate同期的に preventDefault() を発火する必要があります

そのため実質的に ブラウザ組み込みの confirm() のようなAPI しか使えないです

カスタムモーダルを組み込むことが現状できないので、カスタマイズ性が低いです。

この点は大きな制約となりえるでしょう。

導入時に検討すべきこと

実際にプロダクトに導入して感じたことを列挙してみます。


① ヒューマンエラーによる「離脱の抜け道」が生じやすい

👉 onNavigate が効くのは 対象となる <Link> に対してハンドラを仕込んだ場合のみです。誤って通常の <Link> を使うと、そこから自由に遷移できてしまいます。フォーム画面などでは意図せず離脱を許してしまう危険があります。


router.push() はガードできない

👉 シンプルに、止めることができないです。onNavigate が機能するのは <Link> に対してのみであり、App Router 全体の遷移ガードとしては不十分です。


③ フォーム画面で離脱防止用途に使うなら実装コストが高い

👉 画面から見えるリンクすべてに導入する必要があり、抜け漏れの可能性が常にあります。

さいごに

Next.js 15.3 の onNavigate によって App Router でもページ遷移をブロックできるようになりましたが、仕様上の制約により

  • confirmしか使えない
  • <Link> のみ対象で、router.push がガードできない
  • <Link> をカスタマイズしないと離脱防止の完全性を得られない

といったデメリットが残ります。

現状は「軽い遷移確認を行う用途」として割り切って、局所的に利用するのが現実的であり、本格的な離脱防止にはまだ工夫が必要そうです。

参照