Препроцессоры CSS

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


Установка и подключение

Для работы с Haunted достаточно установить пакет через npm:

npm install haunted

Или подключить через CDN:

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

Основные экспортируемые сущности:

  • html — функция для создания шаблонов, аналог JSX.
  • component — функция для регистрации веб-компонента.
  • useState — хук для управления локальным состоянием.
  • useEffect — хук для побочных эффектов.
  • useRef, useContext и другие хуки для расширенной логики.

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

Компонент Haunted создаётся через функцию component, которая принимает функцию-рендерер. Пример простого компонента с состоянием:

import { html, component, 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```, что обеспечивает декларативное описание структуры DOM.
  • Состояние count автоматически вызывает повторный рендер при изменении.
  • События назначаются через @событие=${handler}.

Хуки состояния

useState

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

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

useReducer

Альтернатива useState, подходит для сложной логики:

const [state, dispatch] = useReducer(reducer, initialState);

function reducer(state, action) {
  switch(action.type) {
    case 'increment': return state + 1;
    default: return state;
  }
}

useEffect

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

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

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

Haunted использует lit-html под капотом для рендеринга. Это обеспечивает:

  • Эффективное обновление DOM через диффинг.
  • Декларативное связывание данных и событий.
  • Возможность использовать условные конструкции и циклы:
html`
  <ul>
    ${items.map(item => html`<li>${item}</li>`)}
  </ul>
`
  • События добавляются через @event=${handler}.
  • Атрибуты можно связывать динамически: <div class=${condition ? 'active' : ''}></div>.

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

useRef

Позволяет получить прямой доступ к DOM-элементу:

const inputRef = useRef();

html`<input type="text" ${ref(inputRef)} />`

Контекст (useContext)

Обеспечивает глобальное состояние между компонентами:

const ThemeContext = createContext('light');

function ThemedButton() {
  const theme = useContext(ThemeContext);
  return html`<button class=${theme}>Тема кнопки</button>`;
}

Комбинирование хуков

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


Стиль и интеграция с CSS

Haunted не навязывает способ работы со стилями:

  • Можно использовать встроенные стили:
html`
  <style>
    p { color: red; }
  </style>
  <p>Текст с красным цветом</p>
`
  • Поддерживаются внешние CSS-файлы и CSS-переменные.
  • Интеграция с препроцессорами, такими как SASS или PostCSS, осуществляется на этапе сборки.

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

  • Haunted минимален по размеру (≈2KB), что сокращает время загрузки.
  • Эффективное обновление DOM благодаря lit-html.
  • Лёгкая композиция компонентов без сложных связей.
  • Использование хуков обеспечивает чистоту кода и локализацию состояния.

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

import { html, component, useState, useEffect } from 'haunted';

function TodoList() {
  const [todos, setTodos] = useState([]);
  const [input, setInput] = useState('');

  useEffect(() => {
    const saved = JSON.parse(localStorage.getItem('todos') || '[]');
    setTodos(saved);
  }, []);

  useEffect(() => {
    localStorage.setItem('todos', JSON.stringify(todos));
  }, [todos]);

  const addTodo = () => {
    if(input.trim() === '') return;
    setTodos([...todos, input]);
    setInput('');
  };

  return html`
    <input .value=${input} @input=${e => setInput(e.target.value)} />
    <button @click=${addTodo}>Добавить</button>
    <ul>
      ${todos.map(todo => html`<li>${todo}</li>`)}
    </ul>
  `;
}

customElements.define('todo-list', component(TodoList));

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

  • Состояние управляет списком задач и текущим вводом.
  • useEffect обеспечивает синхронизацию с localStorage.
  • Рендер обновляется автоматически при изменении состояния.

Haunted объединяет простоту Web Components с мощью реактивного подхода, позволяя создавать компактные и легко поддерживаемые интерфейсы. Сильная сторона — минимализм, совместимость с любыми стилями и гибкая работа с хуками.