さかした
🚫【Next.js】タイマー実行中に Link 遷移してしまう問題とその解決策
2025年05月07日
要約を生成中...
Next.js アプリで「学習タイマー」を使って記録を取っている際に、ユーザーがページ遷移やブラウザリロード、戻る操作などをしてしまうと、記録が失われてしまうリスクがあります。
そのため、**ナビゲーションガード(移動前の確認ダイアログ)**を実装して、タイマー実行中の不意な操作を防止していました。
しかし…
<Link href="/user/learning-history">学習履歴</Link>のような Next.js の <Link> を使った遷移では、
キャンセルを押してもページ遷移が発生してしまう問題が起きていました。
Next.js の <Link> は内部で router.push(href) を即座に実行しているため、
document.addEventListener("click", ...) や e.preventDefault() を使っても、イベントのキャンセルが間に合わないのです。
その結果、下記のようなケースで防止できませんでした。
タイマー実行中に <Link> をクリック
確認ダイアログで「キャンセル」を選択
それでもページ遷移が行われてしまう(タイマーリセットされる)
✨ ポイント
<Link> を使わず、router.push(href) を自分で呼び出す
onClick 内で タイマー実行中かどうか をチェック
警告ダイアログを表示し、OK の場合のみ router.push() で遷移
const handleGuardedNav = (href: string) => () => {
if (isLearning) {
const ok = confirm("タイマーが実行中です。このまま移動すると停止されます。続けますか?");
if (!ok) return;
}
router.push(href);
};
<Button onClick={handleGuardedNav("/user/learning-history")}>学習履歴</Button>AppSidebar のリンク(学習管理メニュー)を <Link> から router.push() に切り替え
manualNav というフラグで通常のリンクか手動遷移かを切り替え可能に
将来的にカスタムコンポーネント <GuardedLink /> を作成し、すべて統一予定
Next.js の <Link> は便利だが、即時遷移が強力すぎてキャンセル不可な場面がある
重要な処理中(タイマー、フォーム記入中など)は 手動遷移 + 確認が安全
router.push() を使えば、遷移タイミングを完全に制御できる
<GuardedLink> コンポーネントを共通化し、ガードロジックを抽出
グローバルなタイマー状態(isLearning)を zustand などで共有すればよりスマートに制御可能
このような「Next.js の暗黙の仕様による意図しない動作」は、開発中に気付きにくい落とし穴です。
しかし、router.push() に切り替えることで柔軟な制御が可能になり、UX の向上につながります。
「タイマー付き記録アプリ」などを作っている方の参考になれば嬉しいです!
要約
コメント
まだコメントはありません。