Haunted — это легковесная библиотека для создания реактивных
веб-компонентов на основе стандартов Web Components. Одним из ключевых
механизмов, обеспечивающих реактивность, являются хуки.
Они позволяют управлять состоянием, жизненным циклом компонента и
побочными эффектами аналогично хукам в React. Помимо встроенных хуков
(useState, useEffect,
useReducer), библиотека предоставляет возможность создавать
собственные хуки, расширяя функциональность компонентов
и повышая переиспользуемость логики.
Пользовательский хук — это функция, которая может использовать другие хуки внутри себя и возвращать состояние или функции для управления компонентом. Важные правила:
Вызывать хуки только в теле функции компонента или другого хука. Вне компонента вызов хуков приведет к ошибкам, так как Haunted привязывает состояние к конкретному экземпляру компонента.
Сохранять порядок вызова хуков. Haunted идентифицирует хуки по порядку вызова внутри компонента. Нарушение порядка приведет к некорректной работе состояния.
Возвращать минимальный интерфейс. Пользовательский хук должен предоставлять только то, что нужно для управления состоянием или эффектами, скрывая внутренние детали.
Рассмотрим пример хука для управления счётчиком:
import { useState } from 'haunted';
function useCounter(initialValue = 0) {
const [count, setCount] = useState(initialValue);
const increment = () => setCount(c => c + 1);
const decrement = () => setCount(c => c - 1);
const reset = () => setCount(initialValue);
return { count, increment, decrement, reset };
}
Разбор структуры:
useState используется внутри хука для хранения
состояния.increment, decrement,
reset).Использование хука в компоненте:
import { html, component } from 'haunted';
function CounterComponent() {
const { count, increment, decrement, reset } = useCounter(10);
return html`
<div>
<p>Счёт: ${count}</p>
<button @click=${increment}>+</button>
<button @click=${decrement}>-</button>
<button @click=${reset}>Сброс</button>
</div>
`;
}
customElements.define('counter-component', component(CounterComponent));
Haunted предоставляет useEffect для работы с побочными
эффектами. Пользовательский хук может оборачивать useEffect
для реализации сложной логики.
Пример: хук для автоматического увеличения счётчика через интервал:
import { useState, useEffect } from 'haunted';
function useAutoIncrement(initialValue = 0, interval = 1000) {
const [count, setCount] = useState(initialValue);
useEffect(() => {
const timer = setInterval(() => setCount(c => c + 1), interval);
return () => clearInterval(timer);
}, [interval]);
return { count };
}
Особенности:
useEffect внутри хука автоматически очищает интервал
при размонтировании компонента.[interval]) позволяют корректно
обновлять таймер при изменении интервала.Использование:
function AutoCounter() {
const { count } = useAutoIncrement(0, 500);
return html`<p>Автосчётчик: ${count}</p>`;
}
customElements.define('auto-counter', component(AutoCounter));
Пользовательский хук может инкапсулировать подписку на WebSocket, события или глобальные состояния:
import { useState, useEffect } from 'haunted';
function useWindowSize() {
const [size, setSize] = useState({ width: window.innerWidth, height: window.innerHeight });
useEffect(() => {
const handleResize = () => setSize({ width: window.innerWidth, height: window.innerHeight });
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);
return size;
}
Преимущества:
Пример использования:
function WindowInfo() {
const { width, height } = useWindowSize();
return html`<p>Размер окна: ${width} x ${height}</p>`;
}
customElements.define('window-info', component(WindowInfo));
Хуки могут принимать параметры для динамической настройки поведения. Например, хук для управления таймером с настраиваемым шагом:
import { useState, useEffect } from 'haunted';
function useTimer(step = 1) {
const [time, setTime] = useState(0);
useEffect(() => {
const id = setInterval(() => setTime(t => t + step), 1000);
return () => clearInterval(id);
}, [step]);
return { time };
}
step позволяет изменять логику работы таймера
без изменения самого хука.В Haunted хуки могут использоваться совместно. Например, объединение счётчика и отслеживания размера окна:
function ResponsiveCounter() {
const { count, increment } = useCounter();
const { width } = useWindowSize();
return html`
<div>
<p>Счёт: ${count}</p>
<p>Ширина окна: ${width}</p>
<button @click=${increment}>+</button>
</div>
`;
}
customElements.define('responsive-counter', component(ResponsiveCounter));
useEffect для предотвращения лишних
перерисовок.Пользовательские хуки позволяют создавать мощные, модульные и чистые компоненты, полностью управляемые реактивной логикой Haunted. Они повышают читаемость кода и упрощают поддержку сложных приложений на Web Components.