Подходы к реализации

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


Функциональные компоненты

В Haunted основной единицей является функциональный компонент, который представляет собой обычную JavaScript-функцию. Она принимает props и возвращает template literal с HTML-разметкой, используя встроенную функцию html из Haunted.

import { html, component } from 'haunted';

function MyButton({ label, onClick }) {
  return html`
    <button @click=${onClick}>${label}</button>
  `;
}

customElements.define('my-button', component(MyButton));

Ключевые моменты:

  • component(MyButton) превращает обычную функцию в полноценный веб-компонент.
  • События привязываются с помощью синтаксиса @event, аналогичного Lit.
  • Props доступны как аргументы функции, что упрощает композицию и тестирование.

Использование Hooks

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

  1. useState — локальное состояние компонента:
import { useState } from 'haunted';

function Counter() {
  const [count, setCount] = useState(0);
  return html`
    <div>
      <p>Счётчик: ${count}</p>
      <button @click=${() => setCount(count + 1)}>Увеличить</button>
    </div>
  `;
}
  1. useEffect — побочные эффекты, выполняемые после рендера:
import { useEffect } from 'haunted';

function Logger({ message }) {
  useEffect(() => {
    console.log('Сообщение изменилось:', message);
  }, [message]);

  return html`<p>${message}</p>`;
}
  1. useRef — хранение ссылок на DOM-элементы:
import { useRef } from 'haunted';

function FocusInput() {
  const inputRef = useRef();
  return html`
    <input ref=${inputRef} />
    <button @click=${() => inputRef.current.focus()}>Фокус</button>
  `;
}

Особенности хуков в Haunted:

  • Hooks вызываются строго в верхнем уровне функции компонента.
  • Использование состояния и эффектов делает компоненты полностью реактивными без классов.
  • Массив зависимостей в useEffect позволяет контролировать вызовы побочных эффектов.

Комбинирование компонентов

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

function App() {
  return html`
    <div>
      <my-button label="Клик" @click=${() => alert('Нажато')} />
      <counter-component></counter-component>
    </div>
  `;
}
  • Любой функциональный компонент можно обернуть в component() и использовать как обычный HTML-тег.
  • Props передаются напрямую через атрибуты или как объект при рендеринге.

Управление жизненным циклом

Haunted скрывает большую часть сложности классов, но всё ещё предоставляет доступ к жизненному циклу через хуки:

  • useEffect без зависимостей выполняется после каждого рендера.
  • useEffect с пустым массивом выполняется один раз при монтировании компонента.
  • useEffect с возвращаемой функцией позволяет реализовать очистку ресурсов при размонтировании.
useEffect(() => {
  const id = setInterval(() => console.log('Таймер'), 1000);
  return () => clearInterval(id); // очистка при размонтировании
}, []);

Стилизация компонентов

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

  1. Инлайн-стили через template literal:
return html`
  <button style="background: blue; color: white;">Нажми</button>
`;
  1. Shadow DOM и <style> внутри шаблона:
return html`
  <style>
    button { background: green; color: white; padding: 8px; }
  </style>
  <button>Кнопка</button>
`;
  • Использование Shadow DOM по умолчанию в component() обеспечивает инкапсуляцию стилей.
  • Для глобальных стилей можно использовать обычные CSS-файлы.

Подходы к оптимизации

Haunted минимизирует перерисовку, но есть дополнительные техники:

  • Декомпозиция компонентов: каждый функциональный компонент решает узкую задачу.
  • Избегание лишних состояний: хранить только необходимые данные в useState.
  • Использование useMemo для вычислений, зависящих от props или state.
  • Lazy-loading компонентов через динамический импорт для больших приложений.

Подключение Haunted в проект

Haunted совместим с ES Modules, что позволяет подключать библиотеку напрямую:

<script type="module">
  import { html, component } from 'https://unpkg.com/haunted/haunted.js?module';
</script>

Для сборки через bundler (Webpack, Vite, Rollup) достаточно установить через npm:

npm install haunted

и импортировать функции из пакета.


Haunted сочетает преимущества функционального подхода и стандарта веб-компонентов, позволяя строить реактивные, компактные и легко тестируемые интерфейсы. Использование хуков и template literals делает разработку удобной и предсказуемой, а композиция компонентов обеспечивает масштабируемость больших приложений.