JavaScriptのpushStateでURLを変更する方法10選

JavaScriptのpushStateを使ったURLの変更方法JS
この記事は約19分で読めます。

【サイト内のコードはご自由に個人利用・商用利用いただけます】

この記事では、プログラムの基礎知識を前提に話を進めています。

説明のためのコードや、サンプルコードもありますので、もちろん初心者でも理解できるように表現してあります。

基本的な知識があればサンプルコードを活用して機能追加、目的を達成できるように作ってあります。

※この記事は、一般的にプロフェッショナルの指標とされる『実務経験10,000時間以上』を凌駕する現役のプログラマチームによって監修されています。

サイト内のコードを共有する場合は、参照元として引用して下さいますと幸いです

※Japanシーモアは、常に解説内容のわかりやすさや記事の品質に注力しております。不具合、分かりにくい説明や不適切な表現、動かないコードなど気になることがございましたら、記事の品質向上の為にお問い合わせフォームにてご共有いただけますと幸いです。
(送信された情報は、プライバシーポリシーのもと、厳正に取扱い、処分させていただきます。)

●pushStateとは?

Webアプリケーションを開発していると、ページ遷移をせずにURLを変更したいというシーンに遭遇することがあります。

そんな時に役立つのが、JavaScriptのpushState()メソッドです。

pushState()は、HTML5で導入されたHistory APIの一部で、ブラウザの履歴を操作することができます。

具体的には、現在のURLを変更し、ブラウザの履歴に新しいエントリを追加します。ただし、ページの再読み込みは行われません。

これによって、ユーザーはブラウザの戻る/進むボタンを使って、シームレスにページ間を移動できるようになります。

つまり、pushState()を使えば、Webアプリケーションのユーザーエクスペリエンスを向上させることができるのです。

○pushStateの基本的な使い方

では、実際にpushState()を使ってみましょう。

基本的な使い方は次のようになります。

window.history.pushState(state, title, url);

第1引数のstateは、履歴エントリに関連付けられる状態オブジェクトです。

これは、popstateイベントが発生した際に、イベントオブジェクトのstate プロパティから取得できます。

第2引数のtitleは、現在のところ使用されていません。

将来的な使用に備えて空文字列を指定しておくのが一般的です。

第3引数のurlは、新しいURLを指定します。

これは、絶対パスでも相対パスでも構いません。

○サンプルコード1:シンプルなpushStateの使用例

ここでは、シンプルなpushState()の使用例を紹介します。

// 新しいURLに遷移
window.history.pushState(null, "", "/new-url");

このコードを実行すると、URLが”/new-url”に変更されます。

ただし、ページの再読み込みは行われません。

また、ブラウザの戻るボタンを押すと、元のURLに戻ります。

これは、pushState()によって履歴エントリが追加されたためです。

○pushStateの引数について

pushState()の第1引数には、状態オブジェクトを指定します。

これは、popstateイベントが発生した際に、イベントオブジェクトのstate プロパティから取得できます。

状態オブジェクトは、シリアライズ可能なオブジェクトであれば何でも構いません。

例えば、次のようなオブジェクトを指定できます。

const state = {
  id: 123,
  name: "John Doe"
};
window.history.pushState(state, "", "/new-url");

この状態オブジェクトは、後でpopstateイベントから取得することができます。

window.addEventListener("popstate", function(event) {
  console.log(event.state);
  // 出力結果: {id: 123, name: "John Doe"}
});

状態オブジェクトを使えば、URLに関連する情報をアプリケーション内で管理することができます。

これは、特にシングルページアプリケーション(SPA)を開発する際に役立ちます。

●pushStateとreplaceStateの違い

さて、ここまでpushState()について詳しく見てきましたが、実はHistory APIにはもう1つ、replaceState()というメソッドがあります。

一体、pushState()とreplaceState()の違いは何なのでしょうか?

結論から言うと、pushState()は新しい履歴エントリを追加するのに対し、replaceState()は現在の履歴エントリを置き換えるという違いがあります。

つまり、replaceState()を使うと、ブラウザの戻るボタンで前のページに戻ることができなくなるのです。

少しわかりにくいと思いますので、具体例を見ながら説明していきましょう。

○サンプルコード3:replaceStateの使用例

replaceState()の使用例を見ていきましょう。

// 現在のURLを置き換える
window.history.replaceState(null, "", "/replaced-url");

このコードを実行すると、現在のURLが”/replaced-url”に置き換えられます。

ただし、新しい履歴エントリは追加されません。

そのため、ブラウザの戻るボタンを押しても、前のページには戻れません。

代わりに、その前のページに戻ることになります。

○pushStateとreplaceStateの使い分け

では、pushState()とreplaceState()はどのように使い分ければいいのでしょうか?

基本的には、次のように使い分けるのが一般的です。

  • ページ遷移をシミュレートする場合は、pushState()を使う
  • 現在のURLを変更したいだけの場合は、replaceState()を使う

例えば、シングルページアプリケーション(SPA)では、pushState()を使ってページ遷移をシミュレートすることが多いです。

一方、フォームのサブミット後にURLを変更したい場合などは、replaceState()を使うのが適しています。

ただし、replaceState()を使う場合は注意が必要です。

先ほども述べたように、replaceState()を使うとブラウザの戻るボタンで前のページに戻れなくなります。

これは、ユーザーにとって予期しない動作になる可能性があるからです。

そのため、replaceState()を使う場合は、ユーザーがブラウザの戻るボタンを使って前のページに戻りたいと思うようなシーンでは使わないようにしましょう。

代わりに、pushState()を使ってページ遷移をシミュレートするのが賢明です。

●popstateイベントについて

pushState()やreplaceState()を使ってURLを変更すると、ブラウザの履歴が変化します。でも、ページの再読み込みは発生しません。

じゃあ、URLが変わったことをJavaScriptで検知するにはどうすればいいのでしょうか?

その答えは、ズバリpopstateイベントです!

popstateイベントは、ブラウザの戻る/進むボタンが押されたときや、history.back()やhistory.forward()が呼び出されたときに発生します。

○サンプルコード4:popstateイベントの基本的な使い方

popstateイベントを使うと、ブラウザの履歴が変化したことを検知できます。

基本的な使い方は次のようになります。

window.addEventListener('popstate', function(event) {
  console.log("popstateイベントが発生しました");
  console.log("現在のURL:", window.location.href);
  console.log("イベントに関連付けられた状態:", event.state);
});

このコードでは、window.addEventListenerを使ってpopstateイベントにイベントリスナーを登録しています。

イベントリスナーの中では、コンソールにメッセージを出力しているだけですが、実際のアプリケーションでは、URLが変わったタイミングで必要な処理を行うことになるでしょう。

event.stateには、pushState()やreplaceState()の第1引数で指定した状態オブジェクトが入ります。

これを使えば、URLに関連付けられた情報を取得することができます。

○popstateイベントの発火タイミング

ただし、popstateイベントが発生するタイミングには注意が必要です。

というのも、pushState()やreplaceState()を呼び出したタイミングでは、popstateイベントは発生しないからです。

popstateイベントが発生するのは、次のようなタイミングです。

  • ブラウザの戻る/進むボタンが押されたとき
  • history.back()やhistory.forward()が呼び出されたとき
  • history.go()が呼び出されたとき(引数が0以外の場合)

つまり、JavaScriptでURLを変更しただけでは、popstateイベントは発生しません。ユーザーがブラウザの戻る/進むボタンを押すなどの操作をしてはじめて、popstateイベントが発生するのです。

○サンプルコード5:ブラウザの戻る/進むボタンを検知する

では、ブラウザの戻る/進むボタンが押されたことを検知するには、どうすればいいのでしょうか?

実は、これもpopstateイベントを使えば簡単に実現できます。

window.addEventListener('popstate', function(event) {
  if (event.state === null) {
    console.log("ブラウザの戻る/進むボタンが押されました");
  } else {
    console.log("pushState()またはreplaceState()が呼び出されました");
  }
});

このコードでは、event.stateがnullかどうかで、ブラウザの戻る/進むボタンが押されたのか、それともpushState()またはreplaceState()が呼び出されたのかを判定しています。

ブラウザの戻る/進むボタンが押された場合、event.stateはnullになります。

一方、pushState()またはreplaceState()が呼び出された場合は、event.stateに状態オブジェクトが入ります。

●ブラウザの履歴を操作する

popstateイベントを使えば、ブラウザの履歴が変化したことを検知できることはわかりましたね。

でも、もっと積極的にブラウザの履歴を操作したいと思いませんか?

実は、History APIを使えば、JavaScriptからブラウザの履歴を自在に操作することができるんです。

これを使えば、例えば「戻るボタンを押したときに、特定のページまで一気に戻る」なんていうこともできちゃいます。

○サンプルコード6:履歴をさかのぼる

まずは、履歴をさかのぼる方法から見ていきましょう。

history.back()を使えば、ブラウザの戻るボタンを押したのと同じ効果が得られます。

// 1つ前のページに戻る
history.back();

これだけです。簡単ですね。でも、もっと柔軟に履歴を操作したいこともあるでしょう。

そんなときは、history.go()を使います。

// 3つ前のページに戻る
history.go(-3);

history.go()は、引数に正の数を指定すると履歴を進み、負の数を指定すると履歴をさかのぼります。

上の例では、3つ前のページに戻っています。

○サンプルコード7:履歴を進める

履歴を進めるのも、history.go()を使えば簡単です。

// 2つ先のページに進む
history.go(2);

この例では、2つ先のページに進んでいます。

history.forward()を使っても同じ効果が得られます。

// 1つ先のページに進む
history.forward();

ただし、履歴をさかのぼったり進めたりする場合は注意が必要です。

ユーザーが予期しない動作をすると、混乱を招く可能性があるからです。

必要な場面でのみ、慎重に使うようにしましょう。

○履歴エントリーの情報を取得する

最後に、履歴エントリーの情報を取得する方法を見ていきましょう。

history.state、history.length、location.hrefなどを使えば、現在の履歴エントリーに関する情報を取得できます。

// 現在の状態オブジェクトを取得
console.log(history.state);

// 履歴エントリーの数を取得
console.log(history.length);

// 現在のURLを取得
console.log(location.href);

これらの情報を活用すれば、より高度な履歴の操作が可能になります。

例えば、特定の状態オブジェクトを持つ履歴エントリーを探したり、現在のURLに応じて処理を切り替えたりできます。

ただ、そうすると履歴の操作がややこしくなってきますよね。

私は、履歴の操作は最小限にとどめ、ユーザーを混乱させないようにするのが賢明だと考えています。

●よくあるエラーと対処法

ここまで、pushStateやpopstateイベントについて詳しく見てきましたが、実際に使ってみるとエラーに遭遇することがあります。

そこで、よくあるエラーとその対処法を見ていきましょう。

○pushStateが効かない場合の対処法

まずは、pushStateが効かない場合の対処法です。

pushStateを使ってURLを変更しようとしたのに、URLが変わらないことがあります。

こんな感じのコードを書いたのに、URLが変わらない…。

// pushStateを使ってURLを変更
history.pushState(null, "", "/new-url");

実は、これにはいくつか原因が考えられます。

よくある原因は、サーバー側の設定が適切でないことです。

pushStateを使うと、URLが変わってもページの再読み込みは発生しません。

そのため、サーバー側でも適切な設定が必要になります。

例えば、Apacheの場合は、.htaccessファイルに次のような設定を追加する必要があります。

RewriteEngine On
RewriteBase /
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.html [L]

この設定がないと、pushStateで変更したURLにアクセスしたときに、404エラーが発生してしまいます。

もう1つの原因は、JavaScriptのコードにミスがあることです。

pushStateの使い方を誤っていると、URLが変わらないことがあります。

コードをよく確認して、ミスがないか確かめましょう。

○popstateイベントが発火しない場合の対処法

次は、popstateイベントが発火しない場合の対処法です。

popstateイベントを使って、ブラウザの戻る/進むボタンが押されたことを検知しようとしたのに、イベントが発火しないことがあります。

こんなコードを書いたのに、popstateイベントが発火しない…。

// popstateイベントを監視
window.addEventListener("popstate", function() {
  console.log("popstateイベントが発火しました");
});

この場合も、いくつか原因が考えられます。

1つは、pushStateやreplaceStateを使っていないことです。

popstateイベントは、pushStateやreplaceStateを使ってURLを変更したときに発火します。

これを使っていない場合、popstateイベントは発火しません。

もう1つは、イベントリスナーの登録タイミングが遅いことです。

popstateイベントは、ページが読み込まれた直後に発火することがあります。

そのため、イベントリスナーの登録は、できるだけ早いタイミングで行う必要があります。

○ブラウザバックを禁止したい場合の対処法

最後は、ブラウザバックを禁止したい場合の対処法です。

ユーザーにブラウザの戻るボタンを押されたくない場面があります。

例えば、フォームの入力中などです。

こんな感じのコードを書いて、ブラウザバックを禁止しようとしたのに、うまくいかない…。

// ブラウザバックを禁止
history.pushState(null, null, location.href);
window.addEventListener("popstate", function() {
  history.pushState(null, null, location.href);
});

残念ながら、JavaScriptでブラウザバックを完全に禁止することはできません。

セキュリティ上の理由から、ブラウザの戻る/進むボタンの動作を変更することは許されていないのです。

ただし、代わりの方法はあります。

例えば、フォームの入力中にブラウザバックされると、入力内容が失われてしまうことを警告するメッセージを表示するのです。

// ブラウザバック時に警告メッセージを表示
window.addEventListener("beforeunload", function(event) {
  event.preventDefault();
  event.returnValue = ""; // Chrome対策
});

この方法なら、ユーザーにブラウザバックの危険性を伝えることができます。

ただ、あまり乱用すると、ユーザーの操作性を損なってしまうので注意が必要です。

●pushStateの応用例

さて、ここまでpushStateやpopstateイベントの基本的な使い方について見てきましたが、実際のアプリケーション開発ではどのように活用されているのでしょうか?

実は、pushStateは特にシングルページアプリケーション(SPA)の開発で重宝されています。

SPAとは、1つのHTMLページで構成されるWebアプリケーションのことです。

ページ遷移が発生しないため、ユーザーエクスペリエンスが向上するのが特徴です。

そんなSPAの開発には、pushStateがうってつけなんです。

なぜなら、pushStateを使えば、ページ遷移なしでURLを変更できるからです。

これにより、SPAでもブックマーク可能なURLを実現できます。

では早速、具体的なサンプルコードを見ていきましょう。

○サンプルコード8:シングルページアプリケーション(SPA)での使用例

まずは、SPAでのpushStateの使用例です。

次のようなコードを書くことで、SPAでもブックマーク可能なURLを実現できます。

// ページ遷移をシミュレート
function navigate(url) {
  // コンテンツを更新
  updateContent(url);

  // URLを変更
  history.pushState(null, "", url);
}

// popstateイベントを監視
window.addEventListener("popstate", function() {
  // コンテンツを更新
  updateContent(location.pathname);
});

// コンテンツを更新する関数
function updateContent(url) {
  // URLに応じてコンテンツを切り替える
  switch (url) {
    case "/":
      document.getElementById("content").innerHTML = "<h1>Home</h1>";
      break;
    case "/about":
      document.getElementById("content").innerHTML = "<h1>About</h1>";
      break;
    case "/contact":
      document.getElementById("content").innerHTML = "<h1>Contact</h1>";
      break;
    default:
      document.getElementById("content").innerHTML = "<h1>404 Not Found</h1>";
      break;
  }
}

このコードでは、navigate関数を使ってページ遷移をシミュレートしています。

具体的には、次の処理を行っています。

  • コンテンツを更新する(updateContent関数)
  • history.pushStateを使ってURLを変更する

また、popstateイベントを監視することで、ブラウザの戻る/進むボタンが押されたときにもコンテンツを更新しています。

このようにすることで、SPAでもブックマーク可能なURLを実現できるのです。

ただ、サーバー側の設定も必要になるので注意が必要です。

○サンプルコード9:ReactでのpushStateの使用例

続いて、ReactでのpushStateの使用例を見ていきましょう。

Reactは、FacebookによるJavaScriptのライブラリで、UIの構築に特化しています。

ReactでpushStateを使う場合は、react-routerというライブラリを使うのが一般的です。

ここでは、react-routerを使ったサンプルコードを紹介します。

import { BrowserRouter as Router, Route, Link } from "react-router-dom";

function App() {
  return (
    <Router>
      <div>
        <nav>
          <ul>
            <li>
              <Link to="/">Home</Link>
            </li>
            <li>
              <Link to="/about">About</Link>
            </li>
            <li>
              <Link to="/contact">Contact</Link>
            </li>
          </ul>
        </nav>

        <Route path="/" exact component={Home} />
        <Route path="/about" component={About} />
        <Route path="/contact" component={Contact} />
      </div>
    </Router>
  );
}

function Home() {
  return <h1>Home</h1>;
}

function About() {
  return <h1>About</h1>;
}

function Contact() {
  return <h1>Contact</h1>;
}

このコードでは、react-routerのBrowserRouterコンポーネントを使って、pushStateベースのルーティングを実現しています。

Linkコンポーネントを使って、ページ遷移のリンクを作成しています。

また、Routeコンポーネントを使って、URLに応じてコンポーネントを切り替えています。

まとめ

JavaScriptのpushStateとpopstateイベントを使いこなすことで、ページ遷移なしでURLを変更し、ブラウザの戻る/進むボタンでシームレスにページ間を移動できます。

また、ブラウザの履歴の変化を検知し、より洗練されたWebアプリケーションを開発することができるでしょう。

ただし、使い方を誤ると予期せぬ動作を引き起こす可能性もあるので、十分な注意が必要です。

適切に使いこなすことで、ユーザーエクスペリエンスの向上につなげましょう。

本記事で紹介したサンプルコードを参考に、pushStateとpopstateイベントを活用してみてください。

より高度なWebアプリケーションの開発にチャレンジすることで、スキルアップにつながるはずです。