- SPAで「戻るボタンが壊れる」現象の正体
- 従来のWebではなぜ問題にならなかったのか
- SPAではページ遷移が存在しない
- History APIとは何か
- なぜ壊れるのか
- 典型的な失敗パターン
- 正しい設計:URLを状態のソースにする
- popstateイベントの役割
- よくある誤解
- 注意点
- 最後に
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設計の分岐点になります。