Haunted — это легковесная библиотека для создания веб-компонентов на базе Web Components и реактивного подхода, вдохновлённого React Hooks. Она предоставляет минималистичный API для управления состоянием компонентов и их жизненным циклом, сохраняя совместимость с нативными браузерными технологиями.
Компонент в Haunted создаётся функцией, которая возвращает шаблон в формате lit-html. Основная структура выглядит так:
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 создаёт реактивное состояние внутри
компонента.html из lit-html, позволяя
использовать привязку данных.component оборачивает функцию в полноценный Web
Component.Haunted поддерживает эффекты, аналогичные React Hooks, через
useEffect. Они позволяют выполнять побочные действия при
изменении состояния или при монтировании/размонтировании компонента.
import { useEffect } from 'haunted';
function Logger() {
const [value, setValue] = useState('');
useEffect(() => {
console.log('Значение изменилось:', value);
return () => console.log('Очистка эффекта');
}, [value]);
return html`
<input type="text" .value=${value} @input=${e => setValue(e.target.value)}>
`;
}
Особенности useEffect:
cleanup), которая
срабатывает перед повторным вызовом или при удалении компонента.Haunted позволяет создавать кастомные хуки для повторного использования логики.
function useCounter(initial = 0) {
const [count, setCount] = useState(initial);
const increment = () => setCount(count + 1);
return { count, increment };
}
function CounterDisplay() {
const { count, increment } = useCounter();
return html`
<p>${count}</p>
<button @click=${increment}>+</button>
`;
}
Пользовательские хуки обеспечивают чистую и модульную архитектуру, особенно при большом количестве компонентов с похожей логикой.
Haunted поддерживает основные события жизненного цикла Web Components, но через хуки это упрощается:
useEffect с пустым массивом зависимостей
[] срабатывает один раз при монтировании, аналог
connectedCallback.disconnectedCallback.Пример использования:
useEffect(() => {
console.log('Компонент смонтирован');
return () => console.log('Компонент размонтирован');
}, []);
Haunted автоматически перерисовывает компонент при изменении состояния, но возможны оптимизации:
useMemo для вычислений, зависящих от
состояния, чтобы избежать лишних операций.import { useMemo } from 'haunted';
const doubled = useMemo(() => count * 2, [count]);
Haunted поддерживает реактивную привязку как к свойствам, так и к атрибутам. Свойства компонента можно передавать напрямую, а атрибуты автоматически конвертируются в строки.
function Greeting({ name }) {
return html`<p>Привет, ${name}!</p>`;
}
customElements.define('my-greeting', component(Greeting));
Передача данных через атрибуты:
<my-greeting name="Анна"></my-greeting>
Haunted конвертирует атрибуты в свойства автоматически, позволяя использовать их внутри функции-компонента.
Стили можно применять через <style> внутри шаблона
или через Shadow DOM.
return html`
<style>
p { color: blue; font-weight: bold; }
</style>
<p>${name}</p>
`;
Shadow DOM изолирует стили компонента от внешнего окружения, предотвращая нежелательные конфликты CSS.
Haunted позволяет легко работать с событиями через директиву
@event:
<button @click=${() => dispatchEvent(new CustomEvent('increment'))}>+</button>
Кастомные события могут передавать данные через
detail:
dispatchEvent(new CustomEvent('update', { detail: { value: 42 } }));
Haunted совместим с любыми библиотеками, использующими стандартные DOM API. Это делает возможной интеграцию с Redux, RxJS, D3, и другими, где данные можно просто прокидывать через свойства компонентов.
Haunted сочетает в себе минимализм, реактивность и полную совместимость с Web Components, позволяя строить сложные приложения без избыточного кода. Его хуки, пользовательские состояния и эффекты обеспечивают гибкую архитектуру и высокую производительность.