Haunted — это небольшая библиотека для создания веб-компонентов на базе стандартного Custom Elements API с реактивным подходом, схожим с React Hooks. Основная цель — обеспечить простое управление состоянием компонента, реактивное обновление DOM и интеграцию с нативными браузерными возможностями без необходимости подключения сложных фреймворков.
Библиотека использует hooks для управления состоянием, эффектах и других реактивных процессов. Основные элементы Haunted:
component — функция для создания
компонента.html — шаблонная функция для описания
разметки.useState — реактивное состояние
компонента.useEffect — побочные эффекты.useRef — ссылка на DOM-элемент или
любое значение, сохраняющееся между рендерами.Компоненты в Haunted создаются через функцию component.
Пример:
import { component, html, 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 создает реактивное состояние. Любое изменение
автоматически вызывает повторный рендер компонента.@click) привязываются через синтаксис Lit-html
(@event=${handler}), что обеспечивает корректное обновление
обработчиков при ререндере.component(Counter) превращает обычную функцию в
полноценный custom element.Haunted строится вокруг концепции реактивного состояния:
useStateИспользуется для хранения данных, которые изменяются со временем.
const [value, setValue] = useState(initialValue);
value — текущее состояние.setValue — функция обновления состояния.setValue Haunted автоматически
перерисовывает компонент.useEffectПозволяет выполнять побочные эффекты после рендера:
useEffect(() => {
console.log('Компонент отрендерен');
return () => console.log('Очистка эффекта при размонтировании');
}, [value]);
componentWillUnmount в React).useRefСохраняет ссылку на DOM-элемент или любое значение:
const inputRef = useRef();
return html`<input type="text" ${ref(inputRef)} />`;
Haunted использует html из lit-html,
что позволяет писать декларативные шаблоны. Основные возможности:
${variable}.return html`
<div>
${isLoggedIn ? html`<p>Добро пожаловать!</p>` : html`<p>Вход не выполнен</p>`}
</div>
`;
map:return html`
<ul>
${items.map(item => html`<li>${item}</li>`)}
</ul>
`;
Haunted позволяет объединять несколько хуков в одном компоненте. Например:
function Timer() {
const [seconds, setSeconds] = useState(0);
useEffect(() => {
const id = setInterval(() => setSeconds(s => s + 1), 1000);
return () => clearInterval(id);
}, []);
return html`<p>Прошло секунд: ${seconds}</p>`;
}
useState и
useEffect позволяет строить полноценную реактивную
логику.useEffect.Custom Elements поддерживают связь атрибутов с состоянием. Haunted интегрируется с этим через props:
function Greeting({ name = 'Гость' }) {
return html`<p>Привет, ${name}!</p>`;
}
customElements.define('my-greeting', component(Greeting));
{ name = 'Гость' }.Haunted поддерживает вложенные компоненты без проблем с ререндером:
function Parent() {
return html`<my-counter></my-counter>`;
}
customElements.define('my-parent', component(Parent));
Компоненты могут подписываться на внешние события, используя
useEffect:
useEffect(() => {
function handleResize() {
console.log(window.innerWidth);
}
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);
Haunted рендерит компонент только при изменении состояния. Чтобы избежать лишних ререндеров:
useMemo (при необходимости) для
вычислений, которые не зависят от частых изменений состояния.import { useMemo } from 'haunted';
const doubled = useMemo(() => count * 2, [count]);
useMemo кеширует результат между рендерами, если
зависимости не изменились.Haunted поддерживает scoped CSS через шаблонные строки:
return html`
<style>
p { color: red; font-weight: bold; }
</style>
<p>Красный текст</p>
`;
Haunted легко интегрируется с сторонними библиотеками:
useEffect.useEffect(() => {
const unsubscribe = store.subscribe(() => setState(store.getState()));
return () => unsubscribe();
}, []);
Haunted сочетает легковесность, реактивность и полное использование нативных возможностей браузера, позволяя строить как простые виджеты, так и сложные SPA без тяжеловесных фреймворков. Она опирается на hooks, шаблонные строки и Custom Elements, обеспечивая современный подход к созданию компонентов.