Генераторы проектов

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

Создание функционального компонента

В Haunted компоненты создаются как обычные функции:

import { html, component } from 'haunted';

function Counter({ initial = 0 }) {
  const [count, setCount] = useState(initial);

  return html`
    <div>
      <p>Текущее значение: ${count}</p>
      <button @click=${() => setCount(count + 1)}>Увеличить</button>
    </div>
  `;
}

customElements.define('my-counter', component(Counter));

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

  • html — функция шаблонов, аналог JSX, создаёт виртуальный DOM.
  • component — обёртка функции в полноценный Web Component.
  • useState — хук состояния, аналогичный React, возвращает текущее значение и функцию для его обновления.
  • События привязываются через синтаксис @событие.

Хуки состояния и жизненного цикла

Haunted предоставляет набор хуков, схожих с React:

useState

Создаёт локальное состояние внутри компонента.

const [value, setValue] = useState(initialValue);
  • value — текущее значение состояния.
  • setValue(newValue) — обновляет состояние и вызывает повторный рендер.

useEffect

Позволяет выполнять побочные эффекты, например, подписки или запросы к API.

useEffect(() => {
  const id = setInterval(() => console.log('tick'), 1000);
  return () => clearInterval(id);
}, []);
  • Второй аргумент — массив зависимостей. Если пуст, эффект выполнится один раз при монтировании.

useReducer

Для более сложной логики состояния.

const [state, dispatch] = useReducer(reducer, initialState);
  • reducer — функция (state, action) => newState.
  • dispatch(action) — инициирует обновление состояния.

Рендеринг и шаблоны

Haunted использует lit-html под капотом, что обеспечивает эффективное обновление DOM без полного перерендеринга:

return html`
  <ul>
    ${items.map(item => html`<li>${item}</li>`)}
  </ul>
`;
  • Каждый элемент списка создаётся через html и автоматически отслеживается библиотекой.
  • Обновления происходят только для изменённых узлов, что повышает производительность.

Передача и реактивность свойств

Свойства компонентов передаются как атрибуты или напрямую через объект props:

<my-counter initial="5"></my-counter>

Внутри компонента:

function Counter({ initial }) {
  const [count, setCount] = useState(Number(initial));
}

Haunted автоматически следит за изменением свойств и повторно рендерит компонент при их обновлении.

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

Компоненты Haunted можно использовать друг внутри друга:

function Dashboard() {
  return html`
    <div>
      <my-counter initial="10"></my-counter>
      <my-counter initial="20"></my-counter>
    </div>
  `;
}

customElements.define('my-dashboard', component(Dashboard));
  • Каждый экземпляр имеет собственное состояние.
  • Поведение одного компонента не влияет на другой.

Контекст и глобальное состояние

Haunted поддерживает Context API, позволяя передавать данные глубоко вниз по дереву компонентов без пропсов:

import { createContext, useContext } from 'haunted';

const ThemeContext = createContext('light');

function ThemedButton() {
  const theme = useContext(ThemeContext);
  return html`<button class=${theme}>Кнопка</button>`;
}
  • createContext создаёт контекст с дефолтным значением.
  • useContext позволяет компоненту получать текущее значение.

Встроенные события и реакции

Компоненты Haunted могут реагировать на события нативно и через хуки:

<button @click=${() => alert('Clicked!')}>Нажми меня</button>
  • События привязываются прямо в шаблоне.
  • Использование стрелочной функции гарантирует корректный контекст this.

Примеры интеграции с внешними библиотеками

Haunted легко интегрируется с другими фреймворками и библиотеками:

import { html, component } from 'haunted';
import Chart from 'chart.js/auto';

function ChartComponent({ data }) {
  let canvasRef;

  useEffect(() => {
    new Chart(canvasRef, { type: 'bar', data });
  }, [data]);

  return html`<canvas ${ref(canvasRef)}></canvas>`;
}
  • useEffect используется для инициализации сторонней библиотеки.
  • Можно использовать любой DOM-ориентированный инструмент без конфликтов.

Оптимизация и производительность

  • Haunted минимизирует перерендеры через lit-html diffing.
  • Хуки позволяют избегать лишних вычислений.
  • Компоненты можно мемоизировать при необходимости с помощью useMemo и useCallback.

Рекомендации по структуре проекта

  1. Разделять компоненты по файлам для удобного переиспользования.
  2. Использовать хуки для управления состоянием и побочными эффектами.
  3. Декларативно описывать события и рендер.
  4. Выносить общие стили и контексты на верхний уровень для консистентности.

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