Haunted — это современная библиотека для создания веб-компонентов на базе стандартов Web Components с использованием функционального подхода, схожего с React Hooks. Она обеспечивает реактивное управление состоянием и минималистичный синтаксис для построения UI без необходимости использования сложных фреймворков. Ключевой особенностью Haunted является возможность создавать компоненты как чистые функции, которые управляют своим состоянием через хуки.
Функциональный компонент в Haunted определяется как обычная функция,
которая возвращает шаблон разметки с помощью библиотеки
lit-html. Простейший пример:
import { html, render } from 'lit-html';
import { 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 создаёт реактивное состояние.component преобразует обычную функцию в
веб-компонент.Haunted предоставляет несколько основных хуков:
useState(initialValue)Позволяет хранить локальное состояние компонента. Возвращает массив
[value, setValue].
const [value, setValue] = useState('Hello');
setValue('World'); // обновляет компонент
useEffect(callback, dependencies)Используется для побочных эффектов. Выполняется после рендера и повторно только при изменении зависимостей:
useEffect(() => {
console.log('Компонент обновлён');
}, [count]);
useRef(initialValue)Создаёт объект-ссылку, которая сохраняется между рендерами:
const inputRef = useRef();
<input ref=${inputRef} />;
inputRef.current.focus();
useReducer(reducer, initialState)Позволяет управлять состоянием через редуктор, что удобно для сложной логики:
const [state, dispatch] = useReducer((state, action) => {
switch(action.type) {
case 'increment': return state + 1;
case 'decrement': return state - 1;
default: return state;
}
}, 0);
Haunted позволяет создавать собственные хуки для повторного использования логики. Пользовательский хук — это функция, которая использует другие хуки:
function useCounter(initial = 0) {
const [count, setCount] = useState(initial);
const increment = () => setCount(count + 1);
const decrement = () => setCount(count - 1);
return { count, increment, decrement };
}
function Counter() {
const { count, increment, decrement } = useCounter(5);
return html`
<div>
<p>Счётчик: ${count}</p>
<button @click=${decrement}>-</button>
<button @click=${increment}>+</button>
</div>
`;
}
Особенности пользовательских хуков:
Haunted поддерживает контекст, что позволяет передавать данные глубоко в дерево компонентов без передачи через props:
import { createContext, useContext } from 'haunted';
const ThemeContext = createContext('light');
function ThemedButton() {
const theme = useContext(ThemeContext);
return html`<button class=${theme}>Нажми меня</button>`;
}
function App() {
return html`
<${ThemeContext.Provider} value="dark">
<${ThemedButton}></${ThemedButton}>
</${ThemeContext.Provider}>
`;
}
createContext создаёт контекст с начальным
значением.useContext получает текущее значение из ближайшего
провайдера.Haunted оптимизирует рендеринг через лит-html, обновляя только изменившиеся части DOM. Основные правила:
useState или
useReducer триггерит обновление.useEffect, чтобы избежать неконтролируемых обновлений
DOM.Haunted легко интегрируется с любыми библиотеками, работающими через DOM. Например, подключение стороннего UI-компонента:
function MapComponent({ coords }) {
useEffect(() => {
const map = new SomeMapLibrary.Map('map', { center: coords, zoom: 10 });
return () => map.destroy();
}, [coords]);
return html`<div id="map" style="width:100%;height:300px"></div>`;
}
useEffect для корректного управления жизненным циклом.useEffect, стараясь
объединять связанные действия.Haunted сочетает простоту и мощь функциональных компонентов, позволяя строить масштабируемые веб-приложения с чистой архитектурой и минимальными накладными расходами. Пользовательские хуки становятся центром повторного использования логики и обеспечивают гибкое управление состоянием и побочными эффектами.