Haunted — это библиотека для создания веб-компонентов на основе реактивного подхода в JavaScript, построенная поверх стандартов Web Components. Для работы с Haunted достаточно подключить его через npm или использовать CDN.
Через npm:
npm install haunted
И подключение в модуле:
import { html, component, useState, useEffect } from 'haunted';
Через CDN:
<script type="module">
import { html, component, useState, useEffect } from 'https://unpkg.com/haunted/haunted.js?module';
</script>
Haunted не требует фреймворка или сборщика, его можно использовать с чистым HTML и JavaScript.
В Haunted компонент создаётся функцией, которая возвращает шаблон на
основе html-тегов. Основные элементы:
component — регистрация функции как
веб-компонента.html — создание шаблонов с реактивной
привязкой.useState — управление состоянием
внутри компонента.useEffect — побочные эффекты,
аналогичные React.Пример простого компонента:
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));
Ключевой момент: любое изменение состояния через
setCount автоматически перерисовывает шаблон.
useState возвращает массив из двух элементов: текущего
значения и функции для его обновления. Используется для локального
состояния компонента. Можно создавать несколько состояний:
const [name, setName] = useState('Иван');
const [age, setAge] = useState(30);
Изменение любого из этих состояний вызывает реактивное обновление компонента.
useEffect управляет побочными эффектами. Функция
выполняется после рендера компонента. Можно контролировать частоту
выполнения через массив зависимостей:
useEffect(() => {
console.log('Компонент обновлён');
}, [count]); // вызов только при изменении count
Если массив зависимостей пуст, эффект выполняется один раз при монтировании компонента.
В Haunted можно синхронизировать свойства компонента с его
HTML-атрибутами. Это делается через объект
observedAttributes и привязку в функции компонента:
function Greeting({ name }) {
return html`<p>Привет, ${name}!</p>`;
}
customElements.define('my-greeting', component(Greeting, { observedAttributes: ['name'] }));
Атрибут name автоматически передаётся в компонент как
свойство.
Haunted поддерживает обработку событий с использованием синтаксиса
@событие:
html`<button @click=${handleClick}>Нажми</button>`
Функция handleClick вызывается при срабатывании события.
Можно использовать стрелочные функции для передачи аргументов:
html`<button @click=${() => setCount(count + 1)}>Увеличить</button>`
Для условного рендеринга используется тернарный оператор или функции:
html`${count > 0 ? html`<p>Счётчик больше нуля</p>` : html`<p>Счётчик равен нулю</p>`}`
Для повторяющихся элементов удобно использовать map:
html`
<ul>
${items.map(item => html`<li>${item}</li>`)}
</ul>
`
Haunted позволяет интегрироваться с любыми JS-библиотеками. Например,
для использования библиотек анимации можно обернуть их вызовы в
useEffect:
useEffect(() => {
const anim = new SomeAnimationLibrary(elementRef.current);
anim.start();
return () => anim.stop(); // очистка при размонтировании
}, []);
Это обеспечивает совместимость реактивного подхода с любыми внешними инструментами.
Haunted работает с обычными браузерными DevTools. Для отладки:
<my-counter>.useState шаблон автоматически обновляется, что позволяет
тестировать реактивность напрямую.console.log в эффектах и
обработчиках событий удобно использовать для мониторинга состояния и
жизненного цикла.Совет: удобно использовать WeakMap для
хранения приватных данных компонента без засорения DOM.
Для сложной логики состояния применяют useReducer,
аналогичный React:
function reducer(state, action) {
switch(action.type) {
case 'increment': return { count: state.count + 1 };
case 'decrement': return { count: state.count - 1 };
default: return state;
}
}
const [state, dispatch] = useReducer(reducer, { count: 0 });
useRef позволяет сохранять ссылку на DOM-элемент или
значение между рендерами:
const inputRef = useRef();
html`<input type="text" ref=${inputRef}>`;
Это упрощает работу с нативным DOM.
Haunted совместим с Lit-html, так как использует тот же синтаксис
html. Можно комбинировать Haunted с Lit для более сложных
интерфейсов, используя шаблоны и директивы Lit.
import { html as litHtml } from 'lit-html';
function MixedComponent() {
return html`
${litHtml`<p>Комбинированный шаблон</p>`}
`;
}
Такой подход позволяет использовать преимущества обеих библиотек, сохраняя реактивность Haunted.
Haunted предоставляет мощный и минималистичный инструмент для разработки реактивных веб-компонентов, где управление состоянием, побочные эффекты и работа с DOM интегрированы через понятные и гибкие хуки.