Haunted — это лёгкая библиотека для создания веб-компонентов на основе стандартного API Custom Elements с использованием реактивного подхода, похожего на React, но без виртуального DOM. Основная идея заключается в композиции логики через хуки, что позволяет отделять состояние, побочные эффекты и рендеринг, сохраняя простоту нативного DOM.
В Haunted хуки — это функции, которые управляют состоянием компонента и его жизненным циклом. Они запускаются строго в контексте функции-компонента и позволяют интегрировать реактивность, не создавая сложной иерархии классов.
В Haunted компонент — это функция, возвращающая шаблон разметки. Например, базовый компонент с состоянием может выглядеть так:
import { html, component } from 'haunted';
import { 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 создаёт реактивное состояние, которое
автоматически триггерит повторный рендер при изменении.component оборачивает функцию в веб-компонент, сохраняя
всю реактивность.@событие, который Haunted предоставляет поверх нативного
DOM.useState — базовый хук для хранения данных:
const [value, setValue] = useState(initialValue);
Каждое изменение value вызывает повторный рендер
компонента. Важно: хуки должны вызываться в одном порядке при
каждом рендере, иначе возникает ошибка.
useEffect управляет побочными эффектами:
useEffect(() => {
console.log('Компонент обновлён');
return () => console.log('Очистка эффекта');
}, [count]);
Особенности:
useReducer подходит для сложной логики:
const [state, dispatch] = useReducer(reducer, initialState);
reducer описывает переход состояния по действию.Haunted поддерживает контекст для передачи данных между компонентами, что важно при глубокой иерархии.
import { provide, useContext } from 'haunted';
const ThemeContext = Symbol();
function ThemeProvider({children}) {
provide(ThemeContext, 'dark');
return html`${children}`;
}
function ThemedButton() {
const theme = useContext(ThemeContext);
return html`<button class=${theme}>Кнопка</button>`;
}
provide делает значение доступным для всех
потомков.useContext получает это значение в любом дочернем
компоненте.Haunted строит ререндер на минимальной и детерминированной логике. При изменении состояния происходит:
useEffect и очистка предыдущих эффектов.Ключевой принцип: каждое состояние и эффект привязаны к конкретной функции-компоненту, что упрощает отслеживание изменений и предотвращает утечки памяти.
Эти паттерны формируют философию Haunted: минимализм, функциональная композиция и строгое разделение состояния, эффектов и разметки.
Haunted использует легкий шаблонизатор на основе lit-html, что обеспечивает:
Совместно с хуками это позволяет строить производительные веб-компоненты с реактивным поведением без тяжеловесных библиотек.
Хуки в Haunted не только управляют состоянием и эффектами, но и структурируют компонент вокруг чистых функций, избавляя от лишней сложности классов и наследования. Такой подход:
Основной принцип: каждый компонент — это функция с декларативным описанием UI, а хуки обеспечивают реактивность и контроль жизненного цикла без перегрузки инфраструктуры.