Что такое Haunted

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

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


Создание компонента

Компоненты в Haunted создаются с помощью функции component. Основная структура выглядит следующим образом:

import { component, html, 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));

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

  • html — тег-функция для шаблонов, совместимая с lit-html, позволяет вставлять переменные напрямую.
  • useState — хук состояния, возвращает текущее значение и функцию для его обновления.
  • События указываются через @ перед именем события (@click).

Хуки состояния и эффекты

Haunted использует подход React-подобных хуков для управления состоянием и побочными эффектами. Основные хуки:

useState

Позволяет создавать реактивное состояние:

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

useEffect

Используется для выполнения побочных эффектов после рендера:

useEffect(() => {
  console.log('Компонент обновился');
  return () => console.log('Очистка эффекта при удалении компонента');
}, [value]);
  • Первый аргумент — функция с эффектом.
  • Второй аргумент — массив зависимостей, при изменении которых эффект повторно вызывается.

useRef

Создаёт ссылку на DOM-элемент или произвольное значение:

const inputRef = useRef();
return html`<input ${ref(inputRef)} />`;
  • useRef сохраняет объект между рендерами.
  • В сочетании с ref позволяет напрямую манипулировать DOM.

Передача свойств и атрибутов

Haunted позволяет легко работать с свойствами веб-компонента.

function Greeting({ name }) {
  return html`<p>Привет, ${name}!</p>`;
}

customElements.define('my-greeting', component(Greeting));
  • Свойства передаются при создании элемента:
<my-greeting name="Мария"></my-greeting>
  • Для реактивного обновления свойств нужно определить их в опциях component:
component(Greeting, { observedAttributes: ['name'] });

Работа с событиями

Haunted поддерживает нативные события и делегирование через @event синтаксис:

html`<button @click=${handleClick}>Нажми меня</button>`
  • Любая функция, переданная в @event, будет вызвана с объектом события.
  • Можно комбинировать с хуками для обновления состояния.

Жизненный цикл компонентов

Haunted предоставляет хуки жизненного цикла, аналогичные React:

  • useConnected: вызывается при добавлении компонента в DOM.
  • useDisconnected: вызывается при удалении компонента из DOM.
  • useEffect с пустым массивом зависимостей ([]) можно использовать как componentDidMount / componentWillUnmount.
useEffect(() => {
  console.log('Монтирование компонента');
  return () => console.log('Размонтирование компонента');
}, []);

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

Haunted использует лит-html для рендеринга, что обеспечивает:

  • Минимальные перерисовки.
  • Сравнение виртуального DOM для обновления только изменившихся частей.
  • Поддержку вложенных компонентов и слотов.

Пример вложенного компонента:

function App() {
  return html`
    <div>
      <my-counter></my-counter>
      <my-greeting name="Алексей"></my-greeting>
    </div>
  `;
}

customElements.define('my-app', component(App));

Расширенные возможности

useReducer

Позволяет управлять сложным состоянием через редьюсер:

const [state, dispatch] = useReducer(reducer, initialState);
  • reducer(state, action) возвращает новое состояние.
  • dispatch(action) инициирует обновление состояния.

useContext и провайдеры

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

const ThemeContext = createContext('light');
  • Компоненты могут получать значение контекста через useContext(ThemeContext).
  • Позволяет избежать «прокидывания» props через множество уровней.

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