Пошук уроків, статей та іншого контенту
Зберігатимете дані між сеансами та вкладками за допомогою localStorage і sessionStorage.
Web Storage — це вбудований механізм браузера для збереження невеликих обсягів даних у вигляді пар ключ-значення.
Він містить два сховища:
localStorage — зберігає дані між перезавантаженнями сторінки та сеансами браузера;
sessionStorage — зберігає дані лише протягом поточного сеансу вкладки.
Обидва API мають однаковий інтерфейс:
storage.setItem(key, value);
storage.getItem(key);
storage.removeItem(key);
storage.clear();
storage.key(index);
storage.length;Зазвичай сховище доступне лише для сторінок того самого origin. Origin визначається протоколом, доменом і портом.
Наприклад, ці адреси мають різні origin:
https://example.com
http://example.com
https://api.example.com
https://example.com:8080Дані, збережені для одного origin, не доступні іншому.
localStoragelocalStorage підходить для даних, які мають зберігатися довго:
вибрана тема інтерфейсу;
мова застосунку;
налаштування користувача;
чернетка форми;
простий стан клієнтського застосунку.
localStorage.setItem("theme", "dark");
const theme = localStorage.getItem("theme");
console.log(theme); // "dark"Дані залишаються після:
перезавантаження сторінки;
закриття та повторного відкриття вкладки;
завершення сеансу браузера.
Вони можуть бути видалені користувачем, браузером або самим застосунком.
sessionStoragesessionStorage призначений для даних, які потрібні лише в межах поточного сеансу вкладки:
тимчасовий стан багатокрокової форми;
фільтри сторінки;
стан відкритої вкладки інтерфейсу;
дані, які не потрібно зберігати після закриття вкладки.
sessionStorage.setItem("currentStep", "2");
const currentStep = sessionStorage.getItem("currentStep");
console.log(currentStep); // "2"Дані sessionStorage зазвичай зберігаються після перезавантаження сторінки, але видаляються після закриття вкладки або вікна.
Кожна вкладка має власний sessionStorage. Тому дві вкладки одного сайту можуть мати різні значення одного ключа.
Web Storage зберігає лише рядки. Навіть якщо передати число або булеве значення, воно буде перетворене на рядок:
localStorage.setItem("count", 42);
localStorage.setItem("isLoggedIn", true);
console.log(localStorage.getItem("count")); // "42"
console.log(localStorage.getItem("isLoggedIn")); // "true"Якщо отримане значення потрібно використовувати як число, його треба перетворити:
const count = Number(localStorage.getItem("count") ?? 0);
console.log(count + 1);Для булевого значення можна явно порівняти рядок:
const isLoggedIn = localStorage.getItem("isLoggedIn") === "true";
console.log(isLoggedIn);Не варто використовувати лише Boolean(value) для такого перетворення:
Boolean("false"); // trueБудь-який непорожній рядок у JavaScript є істинним.
Об’єкти та масиви потрібно серіалізувати за допомогою JSON.stringify():
const settings = {
theme: "dark",
language: "uk",
fontSize: 16
};
localStorage.setItem("settings", JSON.stringify(settings));Після отримання рядок потрібно перетворити назад на об’єкт за допомогою JSON.parse():
const rawSettings = localStorage.getItem("settings");
const settings = rawSettings
? JSON.parse(rawSettings)
: {
theme: "light",
language: "uk",
fontSize: 14
};
console.log(settings.theme);Масиви зберігаються так само:
const recentlyViewed = ["article-1", "article-2", "article-3"];
localStorage.setItem(
"recentlyViewed",
JSON.stringify(recentlyViewed)
);
const savedItems = JSON.parse(
localStorage.getItem("recentlyViewed") ?? "[]"
);
console.log(savedItems);JSON.stringify() не зберігає всі типи JavaScript без змін. Наприклад, методи об’єктів будуть втрачені, а Date після парсингу стане рядком.
setItem()Зберігає значення за ключем:
localStorage.setItem("username", "olena");Якщо ключ уже існує, старе значення буде замінене:
localStorage.setItem("username", "olena");
localStorage.setItem("username", "kateryna");
console.log(localStorage.getItem("username")); // "kateryna"getItem()Повертає значення або null, якщо ключ не знайдено:
const username = localStorage.getItem("username");
if (username === null) {
console.log("Користувача не знайдено");
}removeItem()Видаляє один ключ:
localStorage.removeItem("username");clear()Видаляє всі дані поточного сховища для поточного origin:
localStorage.clear();Цей метод не можна використовувати без обережності: він видалить не лише дані поточного компонента, а всі дані застосунку в localStorage.
length і key()Можна отримати кількість ключів і перебрати їх:
for (let index = 0; index < localStorage.length; index += 1) {
const key = localStorage.key(index);
console.log(key, localStorage.getItem(key));
}Порядок ключів не слід вважати важливим або стабільним.
Нижче наведено повний приклад сторінки, яка:
перемикає тему;
зберігає тему в localStorage;
відновлює тему після перезавантаження;
зберігає текст чернетки в sessionStorage;
відновлює чернетку після перезавантаження вкладки;
очищає чернетку за кнопкою.
<!doctype html>
<html lang="uk">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Web Storage</title>
<style>
:root {
font-family: sans-serif;
color-scheme: light;
}
:root.dark {
color-scheme: dark;
}
body {
max-width: 640px;
margin: 40px auto;
padding: 0 16px;
}
textarea {
width: 100%;
min-height: 140px;
box-sizing: border-box;
margin: 16px 0;
}
button {
margin-right: 8px;
padding: 8px 12px;
}
</style>
</head>
<body>
<h1>Налаштування та чернетка</h1>
<button id="themeButton" type="button">
Перемкнути тему
</button>
<textarea
id="draft"
placeholder="Введіть текст чернетки..."
></textarea>
<button id="clearDraftButton" type="button">
Очистити чернетку
</button>
<script>
const themeButton = document.querySelector("#themeButton");
const draftField = document.querySelector("#draft");
const clearDraftButton = document.querySelector("#clearDraftButton");
const savedTheme = localStorage.getItem("theme") ?? "light";
document.documentElement.classList.toggle(
"dark",
savedTheme === "dark"
);
const savedDraft = sessionStorage.getItem("draft") ?? "";
draftField.value = savedDraft;
themeButton.addEventListener("click", () => {
const isDark = document.documentElement.classList.toggle("dark");
const nextTheme = isDark ? "dark" : "light";
localStorage.setItem("theme", nextTheme);
});
draftField.addEventListener("input", () => {
sessionStorage.setItem("draft", draftField.value);
});
clearDraftButton.addEventListener("click", () => {
draftField.value = "";
sessionStorage.removeItem("draft");
});
</script>
</body>
</html>Тему збережено в localStorage, оскільки вона потрібна між сеансами. Чернетку збережено в sessionStorage, оскільки вона має бути тимчасовою для конкретної вкладки.
localStorage, а коли sessionStoragelocalStorage, якщо:значення має переживати закриття вкладки;
користувач очікує, що налаштування запам’ятаються;
дані не є секретними;
обсяг даних невеликий.
Приклади:
localStorage.setItem("language", "uk");
localStorage.setItem("sidebar", "collapsed");sessionStorage, якщо:дані потрібні лише в поточній вкладці;
після закриття вкладки дані більше не актуальні;
різні вкладки повинні мати незалежний стан.
Приклади:
sessionStorage.setItem("checkoutStep", "shipping");
sessionStorage.setItem("searchQuery", "javascript");storageКоли документ змінює localStorage, інші документи того самого origin можуть отримати подію storage.
Подія не запускається в тому самому документі, який виконав setItem(). Це важливо: якщо одна вкладка змінює значення, ця сама вкладка не отримає подію, але інші вкладки того самого сайту можуть її отримати.
window.addEventListener("storage", (event) => {
console.log("Змінено ключ:", event.key);
console.log("Старе значення:", event.oldValue);
console.log("Нове значення:", event.newValue);
console.log("Сховище:", event.storageArea);
});Властивості події:
key — змінений ключ;
oldValue — попереднє значення або null;
newValue — нове значення або null, якщо ключ видалено;
url — адреса документа, який змінив сховище;
storageArea — об’єкт сховища.
Приклад синхронізації теми між вкладками:
window.addEventListener("storage", (event) => {
if (event.key !== "theme") {
return;
}
const theme = event.newValue ?? "light";
document.documentElement.classList.toggle(
"dark",
theme === "dark"
);
});Для синхронізації стану всередині однієї вкладки подія storage не підходить. У такому разі можна безпосередньо викликати функцію оновлення інтерфейсу після запису значення.
Доступ до Web Storage може бути недоступним. Наприклад:
браузер заборонив зберігання для сторінки;
користувач заблокував cookies або подібні механізми;
сховище переповнилося;
застосунок працює в обмеженому середовищі.
Операції зі сховищем можуть завершитися помилкою, тому для надійного коду їх можна обгорнути в try...catch:
function saveSettings(settings) {
try {
localStorage.setItem("settings", JSON.stringify(settings));
return true;
} catch (error) {
console.error("Не вдалося зберегти налаштування", error);
return false;
}
}
const saved = saveSettings({
theme: "dark",
language: "uk"
});
console.log(saved);Якщо дані не є критичними для роботи застосунку, інтерфейс має коректно працювати і без сховища.
Web Storage не призначений для великих файлів, зображень або значних масивів даних. Для таких завдань використовують інші механізми, зокрема IndexedDB або серверне сховище.
Методи Web Storage є синхронними. Виклик setItem() або getItem() блокує виконання JavaScript на час операції.
Для невеликих значень це зазвичай не проблема. Проте не слід часто записувати великі JSON-структури, наприклад на кожен символ введеного тексту у великому редакторі.
localStorage не видаляє дані через певний час самостійно. Якщо дані повинні застарівати, збережіть разом із ними час запису:
const cacheEntry = {
value: "some data",
savedAt: Date.now()
};
localStorage.setItem("cache", JSON.stringify(cacheEntry));
const rawCache = localStorage.getItem("cache");
if (rawCache) {
const cache = JSON.parse(rawCache);
const maxAge = 60 * 1000;
if (Date.now() - cache.savedAt > maxAge) {
localStorage.removeItem("cache");
}
}Дані Web Storage доступні будь-якому JavaScript-коду, який виконується у вашому origin. Тому не зберігайте там:
паролі;
секретні ключі;
токени, які відкривають доступ до критичних ресурсів;
платіжні дані;
іншу конфіденційну інформацію.
Якщо на сторінці з’явиться XSS-вразливість, шкідливий скрипт зможе прочитати localStorage і sessionStorage.
Також дані зі сховища не можна вважати надійними. Користувач або сторонній скрипт може змінити їх, тому сервер завжди повинен самостійно перевіряти права доступу та коректність важливих даних.
Уникайте неструктурованих ключів у великому застосунку. Зручно використовувати префікси:
localStorage.setItem("app:theme", "dark");
localStorage.setItem("app:language", "uk");
localStorage.setItem("app:sidebar", "collapsed");Для даних із різним призначенням можна зберігати один об’єкт:
const appSettings = {
theme: "dark",
language: "uk",
sidebar: "collapsed"
};
localStorage.setItem("app:settings", JSON.stringify(appSettings));Префікси зменшують ризик конфліктів ключів між різними частинами застосунку.
getItem() поверне undefinedЯкщо ключа немає, метод повертає null:
const value = localStorage.getItem("missing");
console.log(value === null); // trueJSON.stringify()localStorage.setItem("user", { name: "Olena" });
console.log(localStorage.getItem("user")); // "[object Object]"Правильний варіант:
localStorage.setItem(
"user",
JSON.stringify({ name: "Olena" })
);JSON.parse() для nullconst value = localStorage.getItem("missing");
const result = JSON.parse(value); // помилкаБезпечніший варіант:
const value = localStorage.getItem("missing");
const result = value ? JSON.parse(value) : null;localStorage не є захищеним сховищем. Не використовуйте його як сейф для паролів або секретних токенів.
clear()localStorage.clear();Це видаляє всі ключі застосунку для поточного origin. Якщо потрібно очистити лише дані конкретного компонента, використовуйте removeItem():
localStorage.removeItem("app:settings");Подія storage не запускається в документі, який змінив сховище. Логіку оновлення поточного інтерфейсу потрібно викликати явно.
Web Storage зручний для налаштувань і невеликих станів, але не для великих колекцій чи файлів. Великі синхронні операції можуть погіршити швидкість інтерфейсу.
localStorage зберігає рядки між сеансами браузера.
sessionStorage зберігає рядки в межах поточної вкладки.
Обидва сховища працюють лише з парами ключ-значення.
Об’єкти й масиви потрібно перетворювати через JSON.stringify() і JSON.parse().
getItem() повертає null, якщо ключ не знайдено.
Подія storage дає змогу реагувати на зміни сховища в інших документах того самого origin.
Web Storage має невеликий обсяг і синхронний API.
Не зберігайте в ньому паролі, секрети та інші конфіденційні дані.
Перед використанням сховища враховуйте його призначення: довготривалі налаштування для localStorage, тимчасовий стан вкладки для sessionStorage.