SPAでブラウザバックが壊れる原因

SPAで「戻るボタンが壊れる」現象の正体

SPA(Single Page Application)を公開すると、一定確率で「ブラウザの戻るボタンが効かない」「戻ったのに画面が前の状態に戻らない」という報告が来ます。サーバログには異常がなく、APIも正常に動いている。それでもユーザは操作不能になります。

これはバグというより、History APIと画面状態の分離によって起きる設計問題です。

結論から言うと、SPAでは「URLの履歴」と「アプリケーションの状態」が別物です。ブラウザバックが壊れるのは、URLだけ戻り、状態が戻っていないためです。

従来のWebではなぜ問題にならなかったのか

従来のWebサイトでは、ページ遷移はHTTPリクエストでした。

GET /products
GET /products/1
GET /cart

ブラウザの戻るボタンは、前のURLへ再リクエストします。サーバがそのページを再生成し、画面も自動的に復元されます。URLと画面が一致していました。

つまり「履歴 = 画面状態」です。

SPAではページ遷移が存在しない

SPAではHTTPリクエストを伴うページ遷移を行いません。代わりにJavaScriptが画面を書き換えます。

router.push("/products/1");

このときブラウザはページを移動していません。アドレスバーの表示だけが変わります。ここで使われているのがHistory APIです。

History APIとは何か

History APIは、ページ遷移を伴わず履歴を追加する仕組みです。

history.pushState({ id: 1 }, "", "/products/1");

これによりURLは変わりますが、ページは再読み込みされません。ここまでは問題ありません。

問題は、ブラウザバック時に起きます。

window.onpopstate = (event) => {
  render(event.state.id);
};

戻るボタンを押すと、ブラウザはURLを戻すだけです。画面復元はJavaScriptの責任になります。

なぜ壊れるのか

多くのSPAは、画面を「現在の状態」から描画しています。履歴を復元していません。

例:

  • 商品一覧 → 商品詳細 → フィルタ変更 → 詳細へ戻る

ユーザが期待するのは「フィルタ適用済み一覧」です。しかしアプリは初期状態の一覧を表示します。URLは同じでも状態が違うからです。

つまり戻るボタンは壊れていません。状態復元を実装していないだけです。

典型的な失敗パターン

状態をメモリだけで管理**

let currentFilter = "popular";

ページを離れると失われます。履歴と連動しません。

URLに状態を持たせない**

URLが
/products
のままだと、並び順やページ番号が復元できません。

API再取得だけに頼る**

戻るたびに最新データを取得すると、履歴時点の状態とは一致しません。

正しい設計:URLを状態のソースにする

SPAでブラウザバックを成立させるには、URLを単なる表示ではなく状態の保存場所として扱う必要があります。

/products?page=2&sort=price

このURLがあれば、画面状態を再構築できます。履歴も復元できます。

重要なのは、URLだけで画面を再現できることです。これを満たさない限り、戻るボタン問題は解決しません。

popstateイベントの役割

戻る操作は次のイベントで検知できます。

window.addEventListener("popstate", (e) => {
  restoreFromURL(location.href);
});

ここで状態復元を行います。API取得ではなく、履歴状態の再現が目的です。

よくある誤解

「routerライブラリを使えば解決する」と思われがちですが、ルータはURL変更を管理するだけです。状態復元までは保証しません。アプリ側の設計責任です。

注意点

localStorageに状態を保存する方法がありますが、履歴単位の復元には向きません。別タブや別セッションと衝突し、予期しない画面になります。

最後に

SPAは「ページ」を持たないアプリケーションです。ブラウザの戻るボタンは本来、ページ履歴のための機能です。そのままでは動きません。

ブラウザバックを正しく動かすとは、履歴管理を実装することです。つまりSPAはUI実装だけでなく、ブラウザそのものの挙動を再現する必要があります。

戻るボタンの不具合は小さなUX問題に見えますが、実際にはアーキテクチャの完成度を示す指標です。URLが単なる見た目なのか、状態の表現なのかを決めることが、SPA設計の分岐点になります。