ストレージイベントは「別タブでの変更を教えてくれる仕組み」
まず一言でいうと、
ストレージイベント(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);
});
JavaScriptevent.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 する
という小さな実験をしてみることです。
「別タブでの変更が、イベントとして飛んでくる」
この感覚を一度自分の目で見ると、
ストレージイベントは一気に“使える道具”になります。
