Haunted — это библиотека для создания веб-компонентов с реактивным
состоянием на основе Web Components и
Hooks, вдохновленных React. Основной инструмент для
работы с состоянием — хук useState. Он позволяет компоненту
хранить локальные данные и автоматически перерисовывать шаблон при их
изменении.
Синтаксис useState в Haunted прост:
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));
Ключевые моменты:
useState возвращает массив из двух
элементов: текущее состояние и функцию для его обновления.setCount) компонент
перерисовывается, а шаблон получает новое
значение.Хотя синтаксис похож, Haunted имеет несколько особенностей:
Web Components в основе В Haunted компонент
создается через customElements.define. Это означает, что
компоненты полностью совместимы с нативными веб-стандартами и могут
использоваться вне Haunted.
Отсутствие Virtual DOM Haunted не использует
виртуальный DOM. Вместо этого шаблонный тег html (из
lit-html) перерисовывает только измененные части DOM. Это снижает
накладные расходы и упрощает обновления.
Связь с атрибутами Состояние
useState не связано автоматически с атрибутами DOM, в
отличие от свойств React. Для синхронизации с атрибутами необходимо
использовать специальные хуки или вручную обновлять атрибуты.
Ограничения на вызов хуков Хуки нужно вызывать только внутри функции компонента. Нарушение этого правила приводит к непредсказуемому поведению. Паттерн строго повторяет React, но без проверки на уровне библиотеки.
Сложные структуры состояния:
function TodoList() {
const [todos, setTodos] = useState([
{ text: 'Изучить Haunted', done: false },
{ text: 'Написать статью', done: false }
]);
const toggleTodo = index => {
const newTodos = todos.map((todo, i) =>
i === index ? { ...todo, done: !todo.done } : todo
);
setTodos(newTodos);
};
return html`
<ul>
${todos.map(
(todo, index) => html`
<li>
<input
type="checkbox"
.checked=${todo.done}
@change=${() => toggleTodo(index)}
/>
${todo.text}
</li>
`
)}
</ul>
`;
}
customElements.define('todo-list', component(TodoList));
Особенности:
todos[0].done = true) не вызовет перерисовку.Haunted поддерживает комбинацию хуков, аналогичных React:
useEffect — реакция на изменения состояния.useReducer — управление сложными состояниями через
редуктор.useRef — доступ к DOM-элементам без повторной
перерисовки.Пример использования useState с
useEffect:
function Timer() {
const [seconds, setSeconds] = useState(0);
useEffect(() => {
const interval = setInterval(() => setSeconds(s => s + 1), 1000);
return () => clearInterval(interval);
}, []);
return html`<p>Прошло секунд: ${seconds}</p>`;
}
customElements.define('timer-counter', component(Timer));
Особенности:
useEffect с пустым массивом зависимостей выполняется
один раз при монтировании компонента.Минимизация количества состояний Создание
большого числа useState для каждого поля может усложнить
код. Лучше объединять связанные данные в один объект состояния.
Мемоизация вычислений Для дорогостоящих
вычислений используется useMemo, чтобы не пересчитывать
результат на каждом обновлении состояния.
Ленивая инициализация useState
принимает функцию для инициализации состояния, если оно
сложное:
const [data, setData] = useState(() => fetchInitialData());
Это позволяет отложить вычисление до первого рендера.
| Характеристика | Haunted | React |
|---|---|---|
| Обновление DOM | Через lit-html, без виртуального DOM | Через виртуальный DOM |
| Связь с атрибутами | Не автоматическая | Частично через props |
| Монтирование компонентов | Web Components native | Виртуальный DOM |
| Состояние сложных объектов | Требуется копирование объектов | Может использовать иммутабельные подходы, но чаще тоже копирование |
| Локальное состояние | Только в компоненте | Только в компоненте |
Haunted useState обеспечивает знакомый интерфейс React,
но с упором на Web Components и прямую работу с DOM.
Понимание этих различий критично для написания эффективных компонентов с
реактивным поведением.