こんにちは、かつコーチです。
前回は「ローディング表示を実装する」というテーマで、非同期処理中のUIについて解説しました。
今回は、ブラウザ側でデータを保存できる仕組み「LocalStorage」と「SessionStorage」を扱います。
「入力途中のフォームの内容を保存しておきたい」「ログイン状態を覚えておきたい」といった場面で欠かせない機能なので、しっかり押さえておきましょう。
LocalStorage・SessionStorageとは?
ブラウザに保存できる「箱」のようなもの
LocalStorageとSessionStorageは、どちらもブラウザに用意されているWeb Storage APIという仕組みの一部です。
ざっくり言うと、「キーと値のペア」でデータをブラウザ内に保存しておける箱のようなものです。
サーバーと通信しなくても、ブラウザ側だけでデータの保存・取得ができるのが最大の特徴です。
Cookieと似たような役割に見えますが、Cookieはサーバーへのリクエストのたびに自動で送信されるのに対して、LocalStorage・SessionStorageはブラウザ内にとどまり続ける点が異なります。
Cookieについては次回の記事で詳しく解説する予定です。
LocalStorageとSessionStorageの違い
名前がよく似ていて混同しやすいのですが、決定的な違いは「データが消えるタイミング」です。
| 項目 | LocalStorage | SessionStorage |
|---|---|---|
| データの保存期間 | 明示的に削除するまで残り続ける | タブ(ウィンドウ)を閉じると消える |
| 共有範囲 | 同じオリジンなら別タブでも共有される | 同じタブ内でのみ有効 |
| 主な用途 | ログイン設定、テーマ設定、入力の下書きなど | 一時的な入力状態、ページ遷移中だけ保持したい値など |
| 保存容量の目安 | 5MB程度(ブラウザによる) | 5MB程度(ブラウザによる) |
私が初めてこの2つを触ったとき、「どっちも似たようなものだから、とりあえずLocalStorageだけ覚えればいいか」と考えていました。
ですが実際に案件で「タブを閉じたら消えてほしい一時データ」をLocalStorageで保存してしまい、ユーザーが別タブを開いたときに情報が意図せず共有されるという不具合を出してしまったことがあります。
「ずっと残したいデータか、そのタブだけで完結してほしいデータか」を最初に意識するだけで、この失敗は防げます。
基本の使い方
データを保存する:setItem
LocalStorageにデータを保存するには、setItem メソッドを使います。
// キー "username" に値 "かつコーチ" を保存する
localStorage.setItem("username", "かつコーチ");
SessionStorageも書き方はまったく同じで、対象が sessionStorage に変わるだけです。
// タブを閉じると消える一時データとして保存する
sessionStorage.setItem("formStep", "2");
データを取得する:getItem
保存したデータを取り出すには getItem を使います。
const username = localStorage.getItem("username");
console.log(username); // "かつコーチ"
存在しないキーを指定した場合は null が返ってくる点に注意してください。
const notExist = localStorage.getItem("notExistKey");
console.log(notExist); // null
データを削除する:removeItem・clear
特定のキーだけ削除したい場合は removeItem、すべて削除したい場合は clear を使います。
// 特定のキーだけ削除する
localStorage.removeItem("username");
// LocalStorage内のデータをすべて削除する
localStorage.clear();
clear() はそのオリジン(サイト)に保存されたすべてのデータを消してしまうので、意図せず他の機能のデータまで消さないように注意が必要です。
オブジェクトや配列を保存したいときの注意点
Web Storageは文字列しか保存できない
ここが初心者がつまずきやすい最大のポイントです。
LocalStorage・SessionStorageは、値として文字列しか保存できません。
オブジェクトや配列をそのまま保存しようとすると、意図しない結果になります。
❌ Before:オブジェクトをそのまま保存してしまう
const user = { name: "かつコーチ", age: 30 };
localStorage.setItem("user", user);
const savedUser = localStorage.getItem("user");
console.log(savedUser); // "[object Object]" という文字列になってしまう
console.log(savedUser.name); // undefined(文字列なのでプロパティにアクセスできない)
setItem にオブジェクトを渡すと、内部で自動的に toString() が呼ばれてしまい、"[object Object]" という無意味な文字列に変換されて保存されてしまいます。
私も初めてこれをやったときは、「保存はできているのに、なぜかデータが取り出せない」と原因が分からず1時間近く悩んだ経験があります。
コンソールで localStorage.getItem("user") を確認して、初めて中身が文字列化されていることに気づきました。
✅ After:JSON.stringifyで文字列に変換してから保存する
const user = { name: "かつコーチ", age: 30 };
// 保存するときはJSON文字列に変換する
localStorage.setItem("user", JSON.stringify(user));
// 取り出すときはJSON.parseでオブジェクトに戻す
const savedUserJson = localStorage.getItem("user");
const savedUser = JSON.parse(savedUserJson);
console.log(savedUser.name); // "かつコーチ"
console.log(savedUser.age); // 30
JSON.stringify() でオブジェクトを文字列に変換して保存し、取り出すときは JSON.parse() で元のオブジェクトに戻す、という流れをセットで覚えておきましょう。
配列を保存する場合も同じ考え方です。
const todoList = ["買い物", "掃除", "勉強"];
localStorage.setItem("todoList", JSON.stringify(todoList));
const savedList = JSON.parse(localStorage.getItem("todoList"));
console.log(savedList); // ["買い物", "掃除", "勉強"]
console.log(savedList[0]); // "買い物"
getItemがnullのときのJSON.parseに注意
もう一つ気をつけたいのが、キーが存在しないときの getItem の返り値です。
getItem は存在しないキーに対して null を返しますが、JSON.parse(null) を実行すると null という文字列扱いになり、意図しない結果を生むことがあります。
// 安全な取り出し方の例
function loadTodoList() {
const json = localStorage.getItem("todoList");
// データが存在しない場合は空配列を返す
return json ? JSON.parse(json) : [];
}
const list = loadTodoList();
console.log(list); // 初回アクセス時は []
json ? JSON.parse(json) : [] のように、データがない場合のフォールバック(代替値)を用意しておくと安全です。
実践:入力中のフォーム内容を自動保存する
入力のたびにLocalStorageへ保存する
実際によく使われるパターンとして、フォームの入力内容を自動保存する例を見てみましょう。
<textarea id="memo" placeholder="ここにメモを入力してください"></textarea>
const memoInput = document.getElementById("memo");
// ページ読み込み時に、保存済みの内容があれば復元する
window.addEventListener("DOMContentLoaded", () => {
const savedMemo = localStorage.getItem("memoDraft");
if (savedMemo) {
memoInput.value = savedMemo;
}
});
// 入力のたびに自動保存する
memoInput.addEventListener("input", () => {
localStorage.setItem("memoDraft", memoInput.value);
});
この仕組みがあれば、入力途中でうっかりページを閉じてしまっても、次回開いたときに続きから書き始められます。
ブログの下書き機能やお問い合わせフォームなど、入力に時間がかかる場面で特に効果を発揮します。
保存イベントの頻度を抑える一歩先の工夫
入力のたびに毎回 setItem を呼ぶと、頻繁なキー入力のたびに保存処理が走ってしまいます。
データ量が多い場合は、一定時間ごとにまとめて保存する「デバウンス」という考え方を組み合わせるとパフォーマンスが安定します。
let saveTimer = null;
memoInput.addEventListener("input", () => {
// 直前のタイマーをキャンセルして、入力が止まってから保存する
clearTimeout(saveTimer);
saveTimer = setTimeout(() => {
localStorage.setItem("memoDraft", memoInput.value);
}, 500);
});
setTimeout については、次々回の記事で改めて詳しく扱います。
まとめ
この記事のポイント
- LocalStorageは明示的に削除するまで残り、SessionStorageはタブを閉じると消える
- 保存・取得・削除は
setItemgetItemremoveItemclearで行う - Web Storageは文字列しか保存できないため、オブジェクトや配列は
JSON.stringify/JSON.parseで変換する getItemがnullを返すケースを考慮して、フォールバック処理を用意しておく
次に読むべき記事
次回は、LocalStorageと似た役割を持つ「Cookie」について、JavaScriptからの操作方法を解説していきます。
→ 次の記事:JavaScriptでCookieを操作する方法