JavaScript 逆引き集 | history.pushState/replaceState

JavaScript JavaScript
スポンサーリンク

history.pushState/replaceState の基本 — history.pushState({}, '', '/page')

history.pushStatehistory.replaceStateブラウザの履歴を操作しつつ URL を書き換えるためのメソッドです。ページを再読み込みせずに URL を変更できるので、SPA(シングルページアプリケーション)や検索条件の反映などに使われます。


基本の使い方

// 履歴に新しいエントリを追加(戻る/進むで辿れる)
history.pushState({ page: 1 }, "", "/page1");

// 現在の履歴を置き換え(戻る/進むでは辿れない)
history.replaceState({ page: 2 }, "", "/page2");
JavaScript
  • 第1引数: 状態オブジェクト(任意のデータ)。popstate イベントで取り出せる。
  • 第2引数: タイトル(現在はほぼ無視される)。空文字でOK。
  • 第3引数: 新しいURL(同一オリジン内でのみ変更可能)。

例題1: タブ切り替えでURLを更新(SPA風)

<button id="tabA">タブA</button>
<button id="tabB">タブB</button>
<div id="content"></div>

<script>
  const content = document.getElementById("content");

  document.getElementById("tabA").addEventListener("click", () => {
    content.textContent = "これはタブAの内容";
    history.pushState({ tab: "A" }, "", "?tab=A");
  });

  document.getElementById("tabB").addEventListener("click", () => {
    content.textContent = "これはタブBの内容";
    history.pushState({ tab: "B" }, "", "?tab=B");
  });

  // 戻る/進むで状態を復元
  window.addEventListener("popstate", (e) => {
    if (!e.state) return;
    content.textContent = `これはタブ${e.state.tab}の内容`;
  });
</script>
HTML
  • ポイント: pushState で履歴を積み、popstate で戻る/進むに対応。
  • URL: ?tab=A?tab=B に変わるがページは再読み込みされない。

例題2: 検索条件をURLに反映(replaceState)

<input id="q" placeholder="検索語">
<button id="search">検索</button>
<div id="result"></div>

<script>
  const q = document.getElementById("q");
  const result = document.getElementById("result");

  document.getElementById("search").addEventListener("click", () => {
    const keyword = q.value.trim();
    result.textContent = `検索結果: ${keyword}`;
    // 履歴を置き換え(戻る/進むでは積まない)
    history.replaceState({ q: keyword }, "", `?q=${encodeURIComponent(keyword)}`);
  });

  // 戻る/進むで復元(replaceStateでもpopstateは発火する)
  window.addEventListener("popstate", (e) => {
    if (e.state?.q) {
      result.textContent = `検索結果: ${e.state.q}`;
      q.value = e.state.q;
    }
  });
</script>
HTML
  • ポイント: replaceState は「履歴を増やさず、現在のエントリを更新」。検索条件のように「戻るで不要」な場合に便利。

実務でのコツ

  • 同一オリジン制約: URL変更は同じドメイン・プロトコル・ポート内でのみ可能。外部サイトには変更できない。
  • popstate イベント: 戻る/進むで発火。state オブジェクトを使って画面状態を復元する。
  • push vs replace:
    • pushState: 履歴を積む → 戻る/進むで辿れる。
    • replaceState: 履歴を置き換える → 戻る/進むでは辿れない。
  • タイトル引数: 現在はほぼ無視される。空文字で問題なし。
  • SPAでの利用: ルーティングライブラリ(React Router, Vue Routerなど)も内部でこれを使っている。

ありがちなハマりポイントと対策

  • URLだけ変えても画面が変わらない:
    • 対策: popstate イベントで状態復元処理を書く。
  • 外部URLを指定してエラー:
    • 対策: 同一オリジン内のパスだけ指定可能。
  • 履歴が増えすぎる:
    • 対策: 状況に応じて replaceState を使う。
  • stateを使わずに復元できない:
    • 対策: 必要な情報は第1引数のオブジェクトに入れておく。

練習問題(ページ番号付きリスト)

<ul id="list"></ul>
<button id="next">次へ</button>
<script>
  const list = document.getElementById("list");
  let page = 1;

  function render() {
    list.innerHTML = "";
    for (let i = 1; i <= 5; i++) {
      const li = document.createElement("li");
      li.textContent = `Page ${page} - Item ${i}`;
      list.appendChild(li);
    }
  }

  document.getElementById("next").addEventListener("click", () => {
    page++;
    render();
    history.pushState({ page }, "", `?page=${page}`);
  });

  window.addEventListener("popstate", (e) => {
    if (e.state?.page) {
      page = e.state.page;
      render();
    }
  });

  render();
</script>
HTML
  • 効果: 「次へ」で履歴が積まれ、戻る/進むでページ番号が復元されます。

直感的な指針

  • 「履歴を積む」なら pushState、「履歴を置き換える」なら replaceState。
  • 必ず popstate で復元処理を書く。
  • SPAや検索条件の反映に使うと、URLと画面状態を同期できる。
タイトルとURLをコピーしました