Haunted — это библиотека для создания веб-компонентов с
использованием реактивного состояния на базе стандартов Web Components и
шаблонов lit-html. Основной принцип управления состоянием в Haunted
строится вокруг хука useState, аналогичного React, но с
особенностями, оптимизированными для нативных элементов.
useStateuseState позволяет создавать реактивные значения внутри
компонента. Синтаксис следующий:
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 — текущее значение состояния.setCount — функция для обновления состояния. Любое
изменение автоматически триггерит повторный рендер компонента.[значение, функция] стандартно
для useState.Haunted обновляет компоненты синхронно в пределах текущего цикла событий. Для сложных сценариев обновления состояния полезно использовать коллбэк:
setCount(prev => prev + 1);
Здесь prev — текущее состояние на момент вызова, что
предотвращает ошибки при множественных последовательных обновлениях.
Для работы с объектами и массивами важно помнить о неизменяемости данных, иначе Haunted не сможет определить изменения и не перерисует компонент.
const [user, setUser] = useState({ name: 'Иван', age: 25 });
function updateName(newName) {
setUser({ ...user, name: newName });
}
Мутация объекта напрямую (user.name = 'Пётр') не
вызовет ререндер, потому что Haunted отслеживает только замену
значения, а не его внутренние изменения.
Можно использовать несколько состояний в одном компоненте:
const [count, setCount] = useState(0);
const [active, setActive] = useState(false);
Каждое состояние независимое, обновление одного не затрагивает другие, но повторный рендер охватывает весь компонент.
Производные значения можно вычислять прямо в теле функции компонента:
const [count, setCount] = useState(0);
const doubled = count * 2;
doubled не хранится в useState, оно
пересчитывается при каждом рендере. Для более сложных вычислений,
зависящих от нескольких состояний, можно использовать комбинацию хуков и
мемоизации.
Состояние можно обновлять на основе внешних событий, например таймеров или веб-сокетов:
const [time, setTime] = useState(new Date());
useEffect(() => {
const interval = setInterval(() => setTime(new Date()), 1000);
return () => clearInterval(interval);
}, []);
useEffect с пустым массивом зависимостей обеспечивает
запуск кода один раз при монтировании компонента и очистку при
размонтировании.
Haunted ререндерит компонент целиком при каждом изменении состояния. Чтобы минимизировать лишние вычисления:
Обновление состояния напрямую связано с событиями. Haunted упрощает
связывание событий с состоянием через синтаксис
@event=${callback}:
<button @click=${() => setCount(count + 1)}>+</button>
События можно использовать не только для кликов, но и для ввода текста, перемещения мыши, изменения элементов формы. Любое изменение через функцию обновления состояния автоматически перерисует компонент с новыми данными.
Для комплексных компонентов часто используют вложенные объекты или массивы с динамическими элементами:
const [tasks, setTasks] = useState([
{ id: 1, title: 'Учить Haunted', done: false },
{ id: 2, title: 'Сделать проект', done: false }
]);
function toggleTask(id) {
setTasks(tasks.map(task =>
task.id === id ? { ...task, done: !task.done } : task
));
}
Такой подход обеспечивает реактивность и корректное обновление DOM при изменении любого элемента коллекции.
setState для изменения
состояния.useState и useEffect.Haunted предоставляет мощный и гибкий механизм управления состоянием, который, при соблюдении принципов неизменяемости и правильного связывания событий, позволяет создавать производительные и легко расширяемые веб-компоненты.