JavaScript | Web API:ストレージ系 API - ストレージイベント

JavaScript JavaScript
スポンサーリンク

ストレージイベントは「別タブでの変更を教えてくれる仕組み」

まず一言でいうと、
ストレージイベント(storage イベント)は「他のタブで localStorage が書き換えられたことを教えてくれる通知」 です。

ポイントはここです。

  • 対象は localStorage(sessionStorage では発火しない)
  • 「同じオリジンの別タブ・別ウィンドウ」で変更があったときにだけ飛ぶ
  • 自分が setItem したタブでは発火しない(他のタブにだけ届く)

つまり、「同じサイトを複数タブで開いているときに、状態を同期したい」場面で効いてきます。


ストレージイベントの基本的な使い方

window に storage イベントリスナーを付ける

使い方の形はシンプルです。

window.addEventListener("storage", (event) => {
  console.log("storage event:", event);
});
JavaScript

このイベントは、
「同じオリジンのどこか別のタブで localStorage が変更されたとき」 に発火します。

例えば、タブ A とタブ B があるとします。

タブ A でこう書き換える。

localStorage.setItem("theme", "dark");
JavaScript

すると、タブ B のほうで storage イベントが発火します。
タブ A では発火しません。

ここがまず一つ目の重要ポイントです。

event から何が分かるのか

storage イベントのコールバックに渡される event には、いくつか便利な情報が入っています。

window.addEventListener("storage", (event) => {
  console.log("key:", event.key);
  console.log("oldValue:", event.oldValue);
  console.log("newValue:", event.newValue);
  console.log("url:", event.url);
  console.log("storageArea === localStorage:", event.storageArea === localStorage);
});
JavaScript

event.key
変更されたキー名(例: "theme")。clear() のときは null

event.oldValue
変更前の値(文字列 or null)。

event.newValue
変更後の値(文字列 or null)。

event.url
変更を行ったページの URL。

event.storageArea
どのストレージか(通常は localStorage)。

これらを使うことで、
「どのキーがどう変わったのか」を別タブ側で知ることができます。


具体例1:タブ間でテーマ設定を同期する

シナリオ

同じサイトを複数タブで開いているとします。
ユーザーがどれか一つのタブで「ダークモード」に切り替えたら、
他のタブも自動的にダークモードに切り替わってほしい。

こういうときに、ストレージイベントが活躍します。

テーマを保存・適用する関数

まず、テーマを localStorage に保存し、画面に適用する関数を用意します。

function saveTheme(theme) {
  localStorage.setItem("theme", theme);
}

function applyTheme(theme) {
  document.documentElement.dataset.theme = theme;
}
JavaScript

ページ読み込み時に、保存済みテーマを適用します。

function loadTheme() {
  const stored = localStorage.getItem("theme");
  if (stored === "light" || stored === "dark") {
    return stored;
  }
  return "light";
}

const initialTheme = loadTheme();
applyTheme(initialTheme);
JavaScript

ボタンでテーマを切り替える

const toggleButton = document.querySelector("#toggle-theme");

toggleButton.addEventListener("click", () => {
  const current = loadTheme();
  const next = current === "light" ? "dark" : "light";
  saveTheme(next);
  applyTheme(next);
});
JavaScript

ストレージイベントで「他タブの変更」を反映する

ここで、ストレージイベントを使います。

window.addEventListener("storage", (event) => {
  if (event.key !== "theme") return;

  const newTheme = event.newValue;
  if (newTheme === "light" || newTheme === "dark") {
    applyTheme(newTheme);
  }
});
JavaScript

これで、

タブ A でテーマを切り替える
→ localStorage の "theme" が書き換わる
→ タブ B に storage イベントが飛ぶ
→ タブ B が applyTheme を呼んで見た目を更新する

という流れが実現できます。

ここでの本質は、
「localStorage を“状態の共有場所”として使い、ストレージイベントで“変更通知”を受け取る」
という設計です。


重要な性質:自分のタブでは発火しない

なぜ「他タブだけ」なのか

ストレージイベントは、
「変更を行ったタブ以外」にだけ飛びます。

タブ A で localStorage.setItem("theme", "dark") を呼ぶと、
タブ B, C, … にはイベントが飛びますが、
タブ A には飛びません。

理由はシンプルで、
「自分で変更したことは自分で知っているはずだから」です。

タブ A は、setItem を呼んだ直後に自分で applyTheme すればよく、
わざわざイベントで教えてもらう必要はありません。

逆に、タブ B は「自分では何もしていないのに、状態が変わった」ので、
イベントで教えてもらう必要があります。

この性質を知らないと、
「storage イベントを付けたのに何も起きない」と勘違いしがちです。

テストするときは、
必ず「別タブを開いて、片方で変更して、もう片方でイベントを見る」
という形で確認してください。


sessionStorage ではストレージイベントが飛ばない理由

sessionStorage は「タブごとのメモ帳」

sessionStorage はタブごとに分かれたストレージでした。

タブ A の sessionStorage と
タブ B の sessionStorage は
完全に別物です。

つまり、
「そもそも共有されていない」ので、
「変更を通知する必要もない」という設計です。

そのため、
storage イベントの対象は localStorage だけ
と覚えておいてください。

「タブ間で状態を共有したい」
→ localStorage + storage イベント

「タブごとに独立した一時状態を持ちたい」
→ sessionStorage(イベントは不要)


具体例2:タブ間でログイン状態を同期する

シナリオ

同じサイトを複数タブで開いているときに、

タブ A でログアウトしたら
タブ B でも自動的にログアウト状態にしたい

というケースを考えます。

ログイン状態を localStorage に持つ

シンプルに、ログイン状態をフラグで持つとします。

function setLoggedIn(isLoggedIn) {
  localStorage.setItem("loggedIn", isLoggedIn ? "1" : "0");
}

function isLoggedIn() {
  return localStorage.getItem("loggedIn") === "1";
}
JavaScript

ページ読み込み時に状態を反映

function updateUI() {
  if (isLoggedIn()) {
    showLoggedInView();
  } else {
    showLoggedOutView();
  }
}

updateUI();
JavaScript

ログイン・ログアウト操作

loginButton.addEventListener("click", () => {
  // 本当はサーバーと通信して認証する
  setLoggedIn(true);
  updateUI();
});

logoutButton.addEventListener("click", () => {
  setLoggedIn(false);
  updateUI();
});
JavaScript

ストレージイベントで他タブも追従させる

window.addEventListener("storage", (event) => {
  if (event.key !== "loggedIn") return;
  updateUI();
});
JavaScript

これで、

タブ A でログアウトする
→ localStorage の "loggedIn""0" になる
→ タブ B に storage イベントが飛ぶ
→ タブ B が updateUI() を呼んでログアウト画面に切り替える

という挙動になります。

ここでもやっていることは、
「localStorage を“共有状態”、storage イベントを“変更通知”として使う」
というパターンです。


ストレージイベントを使うときに意識してほしいこと

「localStorage をメッセージバスとして使う」という発想

ストレージイベントを理解すると、
localStorage を単なる「保存場所」ではなく、
「タブ間通信のための簡易メッセージバス」 としても使えることが見えてきます。

例えば、

localStorage.setItem("broadcast", JSON.stringify({ type: "REFRESH" }));

と書いて、
他のタブの storage イベントでそれを受け取り、
type に応じて処理を分岐する、ということもできます。

ただし、
「書き込んだ値は localStorage に残り続ける」ので、
メッセージ用途に使うときは、
使い終わったら removeItem するなどの工夫が必要です。

初心者として押さえておきたいポイント

最後に、あなたの頭の中に残しておいてほしいのは、これです。

ストレージイベントは window"storage" イベントとして受け取る
対象は localStorage(sessionStorage では発火しない)
「同じオリジンの別タブ・別ウィンドウ」で変更があったときだけ飛ぶ
自分が setItem したタブでは発火しない
event.key / oldValue / newValue / url から「何がどう変わったか」が分かる
タブ間でテーマやログイン状態を同期するのにとても便利

一番のおすすめ練習は、
実際にブラウザで同じページを 2 タブ開いて、

片方で localStorage を書き換える
もう片方で storage イベントを受け取って console.log する

という小さな実験をしてみることです。

「別タブでの変更が、イベントとして飛んでくる」
この感覚を一度自分の目で見ると、
ストレージイベントは一気に“使える道具”になります。

タイトルとURLをコピーしました