Imagine filling out a long form, refreshing the page by accident, and losing everything. The Web Storage API is a built-in key-value store for strings, and it helps preserve that progress. We will cover localStorage and sessionStorage in the order of concept → code → reason.
Key terms
- Web Storage API: a simple browser storage system that keeps key-value strings.
localStorage: persistent storage that survives revisits to the same origin.sessionStorage: tab-scoped storage that disappears when the tab closes.JSON.stringify/JSON.parse: functions for serializing and restoring objects or arrays.- TTL (Time To Live): storing an expiration timestamp alongside a value so you can expire it later.
Core ideas
localStorage: scoped to the origin and sticks around until deleted by the user or by code.sessionStorage: scoped to the current tab, great for drafts or temporary filter values.- JSON serialization: storage only holds strings, so wrap data with
JSON.stringifyand unwrap withJSON.parse. storageevent: fires in other tabs of the same origin wheneverlocalStoragechanges, allowing real-time sync.- TTL: because storage has no notion of expiry, store
{ value, expiresAt }yourself.
Code examples
const STORAGE_KEY = "starter-dashboard";
function loadState(defaultValue) {
try {
const raw = localStorage.getItem(STORAGE_KEY);
if (!raw) return defaultValue;
return JSON.parse(raw);
} catch (error) {
console.error("Failed to parse storage", error);
return defaultValue;
}
}
function saveState(state) {
localStorage.setItem(STORAGE_KEY, JSON.stringify(state));
}
const initial = loadState({ todos: [], theme: "light" });
const state = { ...initial };
function update(partial) {
Object.assign(state, partial);
render();
saveState(state);
}
window.addEventListener("storage", (event) => {
if (event.key !== STORAGE_KEY || !event.newValue) return;
const next = JSON.parse(event.newValue);
Object.assign(state, next);
render();
});
const formDraftKey = "signup-draft";
function saveDraft(event) {
const formData = new FormData(event.currentTarget);
const draft = Object.fromEntries(formData.entries());
sessionStorage.setItem(formDraftKey, JSON.stringify(draft));
}
function restoreDraft(form) {
const raw = sessionStorage.getItem(formDraftKey);
if (!raw) return;
const draft = JSON.parse(raw);
Object.entries(draft).forEach(([name, value]) => {
const input = form.elements.namedItem(name);
if (input instanceof HTMLInputElement) input.value = value;
});
}
const form = document.querySelector(".signup-form");
form?.addEventListener("input", debounce(saveDraft, 400));
if (form) restoreDraft(form);
function setWithExpiration(key, value, ttlMs) {
const payload = { value, expiresAt: Date.now() + ttlMs };
localStorage.setItem(key, JSON.stringify(payload));
}
function getWithExpiration(key) {
const raw = localStorage.getItem(key);
if (!raw) return null;
const payload = JSON.parse(raw);
if (Date.now() > payload.expiresAt) {
localStorage.removeItem(key);
return null;
}
return payload.value;
}
Why it matters
localStoragekeeps prototypes trustworthy by surviving refreshes and restarts.sessionStoragedrafts restore long forms when someone navigates away briefly.- The
storageevent and TTL pattern prevent UIs from drifting apart across tabs.
Practice
- Follow along: connect
loadState/saveStateto your todo data and confirm it survives refreshes. - Extend: keep form drafts in
sessionStorage, and in a second tab sync the list via thestorageevent. - Debug: trigger JSON parse errors or quota issues on purpose, log them, and fall back to safe defaults.
- Done when: state saves automatically without a dedicated button and cross-tab edits trigger immediate re-rendering.
Wrap-up
Web storage acts like a “tiny server” inside the browser. Next we will use the persisted data alongside the event loop and debounce/throttle controls to boost responsiveness.
💬 댓글
이 글에 대한 의견을 남겨주세요