Upgrade to Pro — share decks privately, control downloads, hide ads and more …

URLは変わるのに画面が更新されない ── Next.js 16.2 ルーターキャッシュのバグを追う

URLは変わるのに画面が更新されない ── Next.js 16.2 ルーターキャッシュのバグを追う

Avatar for yuki yamazaki

yuki yamazaki

July 20, 2026

More Decks by yuki yamazaki

Other Decks in Programming

Transcript

  1. 何が起きたか 1 Next.js を 15 → 16.2 に上げたら、複数選択フィルタが壊れた 同じキーが並ぶURLで、末尾でない値を外す ?tag=react&tag=nextjs

    → ✗ ✓ URL は ?tag=nextjs に変わる でも一覧は古いまま。react も外れない ✗ ローディング表示すら出ない ✗ ▶ 16.2.10:チェックを外してもURLしか変わらない コードは何も変えていない。変えたのは Next.js のバージョンだけ。 Next.js 16.2 Router Cache Bug 2
  2. 2 まず切り分ける 「URLは変わるのに画面が変わらない」→ まずどこが原因かを絞る 症状 URL は変わるが 一覧が更新されない → 試す

    その状態で ページをリロード → 結果 一覧は正しく 更新された わかったこと サーバーは ?tag=nextjs を受け取れば正しく描画できる。 おかしいのは クライアントのルート遷移だけ → 怪しいのは クライアントのルーターキャッシュ Next.js 16.2 Router Cache Bug 3
  3. 3 Issue を見つける next.js router cache search params で検索 →

    同じ症状の Issue に到達 #92152 Next 16.2 router cache issue, if search param name is used multiple times =「同じ検索パラメータ名を複数回使ったとき」── まさに自分が踏んだ状況 参考 github.com/vercel/next.js/issues/92152 コメントを追うと • 複数バージョンで再現 16.2.1 / 16.2.4 / 16.2.5 / 16.2.6 で確認 • router.refresh() は罠 回避に使うとアナリティクスが二重発火する副作用 • 16.1 に戻せば直る “My only fix is to roll back to 16.1” というコメント Next.js 16.2 Router Cache Bug 4
  4. 5 最小構成で再現する タグで記事を絞り込む一覧ページを組んで検証(dev / 本番ビルドとも同結果) 操作 Next.js 16.1.7 Next.js 16.2.10

    末尾でない値 (react) を外す 正しく更新される URLは変わるが一覧は古い(バグ) 末尾の値 (nextjs) を外す 正しく更新される 正しく更新される バグ状態でリロード ― サーバーは正しく描画する 気になる点が2つ ① なぜ末尾の値を外すときはバグらない? Next.js 16.2 Router Cache Bug ② なぜリロードすると直る? 6
  5. 原因はキャッシュキーの衝突 7 クライアントがキャッシュキーを組み立てる箇所で、こう変換している Object.fromEntries(new URLSearchParams(renderedSearch)) URLSearchParams は全ての値を持つが、オブジェクトは同じキーを2つ持てない → 末尾の値だけが残る Object.fromEntries(new

    URLSearchParams('tag=react&tag=nextjs')) // → { tag: 'nextjs' } ← react が消える 遷移前 ?tag=react&tag=nextjs 遷移後 ?tag=nextjs → → { tag: "nextjs" } { tag: "nextjs" } 別々の URL なのに 同じキャッシュキー になり 衝突する Next.js 16.2 Router Cache Bug 8
  6. 8 2つとも説明がつく ① 末尾の値 (nextjs) を外してもバグらない 遷移後は ?tag=react → キーは

    { tag: "react" } 遷移前の { tag: "nextjs" } と別物 → 衝突しない ② リロードすると直る フルリロードは サーバーで描画し直す 壊れたクライアントキャッシュを経由しない 補足:同じキーを潰す書き方はクライアント側に3箇所あり、うち1つは 16.2.0 で新しく入ったコード。落とし穴を踏むコードが増えて 表面化した。 Next.js 16.2 Router Cache Bug 9
  7. 9 どう対応したか 修正PR #93368 は執筆時点(2026年7月)で未マージ。手元で取れる策は3つ △ router.refresh() で再取得 Issue報告どおり、イベント二重発火などの副作用が出ることがある △

    クエリを別形式(カンマ区切り等)に変える フィルタUI全体の作りに手が入る ✓ 16.1 系にダウングレード ← 採用 変更の少なさと確実性を優先。上流修正が入ったら戻す 修正PR github.com/vercel/next.js/pull/93368 Next.js 16.2 Router Cache Bug 10