Библиотека Haunted строится на концепциях веб-компонентов и реактивного состояния, вдохновлённого React-хуками. Важным аспектом разработки компонентов является управление состоянием, которое должно сохраняться между перерисовками и, при необходимости, между сессиями. Персистентность состояния позволяет сохранять данные компонента в локальном хранилище, сеансовом хранилище или других источниках, обеспечивая непрерывность пользовательского опыта.
Основной инструмент для работы с состоянием в Haunted — хук
useState. Он обеспечивает реактивность и триггерит
обновление DOM при изменении значения:
import { html, component, useState } from 'haunted';
function Counter() {
const [count, setCount] = useState(0);
return html`
<div>
<p>Счётчик: ${count}</p>
<button @click=${() => setCount(count + 1)}>Увеличить</button>
</div>
`;
}
customElements.define('my-counter', component(Counter));
Здесь count существует только во время жизни компонента.
При перезагрузке страницы значение сбрасывается. Для персистентности
нужно хранить состояние вне компонента.
localStoragelocalStorage предоставляет возможность сохранять данные
между сессиями браузера. Для интеграции с Haunted используется эффект
useEffect и чтение/запись данных при инициализации и
изменении состояния:
import { html, component, useState, useEffect } from 'haunted';
function PersistentCounter() {
const [count, setCount] = useState(() => {
const saved = localStorage.getItem('count');
return saved ? Number(saved) : 0;
});
useEffect(() => {
localStorage.setItem('count', count);
}, [count]);
return html`
<div>
<p>Счётчик: ${count}</p>
<button @click=${() => setCount(count + 1)}>Увеличить</button>
</div>
`;
}
customElements.define('persistent-counter', component(PersistentCounter));
Ключевые моменты:
useState(() => ...) позволяет прочитать значение из
localStorage только один раз при создании компонента.useEffect с зависимостью [count]
обеспечивает синхронизацию состояния с хранилищем после каждого
изменения.sessionStorageЕсли требуется сохранять состояние только на время текущей сессии,
применяется sessionStorage. Подход идентичен
localStorage, меняется только API:
function SessionCounter() {
const [count, setCount] = useState(() => {
const saved = sessionStorage.getItem('count');
return saved ? Number(saved) : 0;
});
useEffect(() => {
sessionStorage.setItem('count', count);
}, [count]);
return html`
<div>
<p>Счётчик сессии: ${count}</p>
<button @click=${() => setCount(count + 1)}>Увеличить</button>
</div>
`;
}
sessionStorage очищается при закрытии вкладки, поэтому
подходит для временных данных.
Для объектов и массивов персистентность требует сериализации:
function TodoList() {
const [todos, setTodos] = useState(() => {
const saved = localStorage.getItem('todos');
return saved ? JSON.parse(saved) : [];
});
useEffect(() => {
localStorage.setItem('todos', JSON.stringify(todos));
}, [todos]);
const addTodo = task => setTodos([...todos, { task, done: false }]);
const toggleTodo = index => setTodos(
todos.map((t, i) => i === index ? { ...t, done: !t.done } : t)
);
return html`
<div>
<ul>
${todos.map((t, i) => html`
<li>
<input type="checkbox" .checked=${t.done} @change=${() => toggleTodo(i)}>
${t.task}
</li>
`)}
</ul>
<button @click=${() => addTodo('Новая задача')}>Добавить</button>
</div>
`;
}
Выделение ключевых моментов:
localStorage через эффект.map,
spread operator).При работе с персистентным хранилищем важно учитывать возможные ошибки:
JSON.parse) может вызвать
исключение.storage:useEffect(() => {
const handler = e => {
if (e.key === 'count') setCount(Number(e.newValue));
};
window.addEventListener('storage', handler);
return () => window.removeEventListener('storage', handler);
}, []);
useState.localStorage или sessionStorage.useState и синхронизацию с хранилищем:function usePersistentState(key, defaultValue) {
const [state, setState] = useState(() => {
const saved = localStorage.getItem(key);
return saved ? JSON.parse(saved) : defaultValue;
});
useEffect(() => {
localStorage.setItem(key, JSON.stringify(state));
}, [key, state]);
return [state, setState];
}
Такой подход упрощает многократное использование и делает код компонентов более читаемым и поддерживаемым.
Персистентность состояния в Haunted обеспечивает сочетание реактивности и долговременного хранения данных, что особенно важно для сложных веб-приложений, где пользовательские данные должны сохраняться между обновлениями интерфейса и перезапусками браузера.