Haunted — это библиотека для создания веб-компонентов на основе Web Components с реактивной моделью, вдохновлённой React Hooks. Одним из ключевых инструментов в Haunted является использование хуков, которые позволяют управлять состоянием, побочными эффектами и жизненным циклом компонента. Композиция хуков делает код более модульным и повторно используемым.
Haunted предоставляет набор хуков, таких как:
useState — управление локальным состоянием.useEffect — выполнение побочных эффектов после
рендера.useReducer — сложная логика состояния.useRef — сохранение мутабельных ссылок на данные.useContext — доступ к контексту компонента.Каждый хук должен вызываться в верхнем уровне тела функции компонента, что сохраняет предсказуемость работы.
import { html, component, useState, useEffect } from 'haunted';
function Counter() {
const [count, setCount] = useState(0);
useEffect(() => {
const interval = setInterval(() => setCount(c => c + 1), 1000);
return () => clearInterval(interval);
}, []);
return html`<div>Count: ${count}</div>`;
}
customElements.define('my-counter', component(Counter));
Композиция хуков позволяет создавать мелкие, изолированные хуки, которые можно объединять для построения сложного поведения компонента. Это повышает повторное использование кода и упрощает тестирование.
Разделение логики по ответственности Один хук должен отвечать за одну задачу. Например, отдельные хуки для:
useFormState)useWebSocket)useAnimationFrame)Композиция через вложенные вызовы Хуки могут вызывать другие хуки внутри себя, если они остаются на верхнем уровне своей функции.
function useTimer(initial = 0) {
const [time, setTime] = useState(initial);
useEffect(() => {
const interval = setInterval(() => setTime(t => t + 1), 1000);
return () => clearInterval(interval);
}, []);
return time;
}
function TimerDisplay() {
const time = useTimer();
return html`<div>Time: ${time}</div>`;
}
customElements.define('timer-display', component(TimerDisplay));
В этом примере useTimer является вложенным,
переиспользуемым хуком, который можно подключать к любому
компоненту.
1. Хуки с параметрами Позволяют настраивать поведение внутри компонента, не дублируя логику:
function useCounter(step = 1) {
const [count, setCount] = useState(0);
const increment = () => setCount(c => c + step);
const decrement = () => setCount(c => c - step);
return { count, increment, decrement };
}
function CounterComponent() {
const { count, increment, decrement } = useCounter(2);
return html`
<div>
<button @click=${decrement}>-</button>
${count}
<button @click=${increment}>+</button>
</div>
`;
}
customElements.define('counter-component', component(CounterComponent));
2. Хуки с эффектами и очисткой ресурсов
Использование useEffect внутри пользовательского хука
позволяет автоматически управлять подписками и таймерами:
function useDocumentTitle(title) {
useEffect(() => {
const previous = document.title;
document.title = title;
return () => { document.title = previous; };
}, [title]);
}
function Page() {
useDocumentTitle('Главная страница');
return html`<h1>Контент страницы</h1>`;
}
customElements.define('page-component', component(Page));
3. Комбинирование нескольких хуков Можно объединять несколько маленьких хуков в один “составной” хук:
function useTimerWithDocumentTitle() {
const time = useTimer();
useDocumentTitle(`Время: ${time}`);
return time;
}
function TimerPage() {
const time = useTimerWithDocumentTitle();
return html`<p>Прошло секунд: ${time}</p>`;
}
customElements.define('timer-page', component(TimerPage));
Использование композиции делает компоненты короткими и
понятными, выделяя отдельные аспекты поведения. Вместо одной
громоздкой функции с множеством useState и
useEffect появляется набор маленьких хуков, каждый из
которых отвечает за конкретную задачу. Такой подход упрощает:
function useAuthentication() {
const [user, setUser] = useState(null);
useEffect(() => {
const token = localStorage.getItem('token');
if (token) setUser({ name: 'Demo User' });
}, []);
return user;
}
function useGreeting() {
const user = useAuthentication();
return user ? `Привет, ${user.name}!` : 'Привет, гость!';
}
function GreetingComponent() {
const greeting = useGreeting();
return html`<h2>${greeting}</h2>`;
}
customElements.define('greeting-component', component(GreetingComponent));
Здесь три уровня композиции: useAuthentication →
useGreeting → GreetingComponent. Такой подход
облегчает повторное использование логики аутентификации и приветствия в
других частях приложения.
Композиция хуков в Haunted — это ключевой инструмент для построения масштабируемых и чистых веб-компонентов, позволяющий разделять ответственность, повторно использовать логику и управлять сложными состояниями без хаоса.