Философия хуков в веб-компонентах

Haunted — это лёгкая библиотека для создания веб-компонентов на основе стандартного API Custom Elements с использованием реактивного подхода, похожего на React, но без виртуального DOM. Основная идея заключается в композиции логики через хуки, что позволяет отделять состояние, побочные эффекты и рендеринг, сохраняя простоту нативного DOM.

В Haunted хуки — это функции, которые управляют состоянием компонента и его жизненным циклом. Они запускаются строго в контексте функции-компонента и позволяют интегрировать реактивность, не создавая сложной иерархии классов.


Функции-компоненты

В Haunted компонент — это функция, возвращающая шаблон разметки. Например, базовый компонент с состоянием может выглядеть так:

import { html, component } from 'haunted';
import { 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 предоставляет поверх нативного DOM.

Управление состоянием через хуки

useState — базовый хук для хранения данных:

const [value, setValue] = useState(initialValue);

Каждое изменение value вызывает повторный рендер компонента. Важно: хуки должны вызываться в одном порядке при каждом рендере, иначе возникает ошибка.

useEffect управляет побочными эффектами:

useEffect(() => {
  console.log('Компонент обновлён');
  return () => console.log('Очистка эффекта');
}, [count]);

Особенности:

  • Эффект вызывается после рендера.
  • Второй аргумент — массив зависимостей, изменения которых триггерят повторный вызов эффекта.
  • Возвращаемая функция выполняется при размонтировании компонента или перед следующим вызовом эффекта.

useReducer подходит для сложной логики:

const [state, dispatch] = useReducer(reducer, initialState);
  • reducer описывает переход состояния по действию.
  • Позволяет централизовать управление состоянием, аналогично Redux, но локально в компоненте.

Контекст и композиция

Haunted поддерживает контекст для передачи данных между компонентами, что важно при глубокой иерархии.

import { provide, useContext } from 'haunted';

const ThemeContext = Symbol();

function ThemeProvider({children}) {
  provide(ThemeContext, 'dark');
  return html`${children}`;
}

function ThemedButton() {
  const theme = useContext(ThemeContext);
  return html`<button class=${theme}>Кнопка</button>`;
}
  • provide делает значение доступным для всех потомков.
  • useContext получает это значение в любом дочернем компоненте.
  • Контекст помогает избежать “пробрасывания пропсов” через несколько уровней DOM.

Жизненный цикл и ререндер

Haunted строит ререндер на минимальной и детерминированной логике. При изменении состояния происходит:

  1. Вычисление нового шаблона.
  2. Диффинг и обновление DOM без полной перерисовки.
  3. Вызов useEffect и очистка предыдущих эффектов.

Ключевой принцип: каждое состояние и эффект привязаны к конкретной функции-компоненту, что упрощает отслеживание изменений и предотвращает утечки памяти.


Практические паттерны

  1. Локальное состояние через useState — для простых счётчиков, флагов, текстовых полей.
  2. Сложная логика через useReducer — управление формами, списками, анимациями.
  3. Синхронизация с внешними API через useEffect — запросы данных, подписки на события, таймеры.
  4. Передача данных через контекст — темы, авторизация, настройки, общие сервисы.

Эти паттерны формируют философию Haunted: минимализм, функциональная композиция и строгое разделение состояния, эффектов и разметки.


Оптимизация рендеринга

Haunted использует легкий шаблонизатор на основе lit-html, что обеспечивает:

  • Повторное использование элементов DOM.
  • Обновление только изменённых узлов.
  • Минимизацию затрат на виртуальный DOM.

Совместно с хуками это позволяет строить производительные веб-компоненты с реактивным поведением без тяжеловесных библиотек.


Итоговая философия хуков

Хуки в Haunted не только управляют состоянием и эффектами, но и структурируют компонент вокруг чистых функций, избавляя от лишней сложности классов и наследования. Такой подход:

  • Упрощает тестирование.
  • Делает компоненты предсказуемыми.
  • Позволяет создавать переиспользуемые логические блоки.

Основной принцип: каждый компонент — это функция с декларативным описанием UI, а хуки обеспечивают реактивность и контроль жизненного цикла без перегрузки инфраструктуры.