Принцип работы состояния

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


Хук useState

Функция useState позволяет объявить состояние в компоненте:

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));

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

  • useState(initialValue) возвращает массив из двух элементов: текущее значение состояния и функцию для его обновления.
  • При вызове функции обновления (setCount) компонент автоматически перерендеривается.
  • Состояние сохраняется между рендерами, несмотря на многократные вызовы функции компонента.

Важная деталь: порядок вызовов useState критически важен. Изменение порядка нарушит соответствие значений состояний между рендерами.


Механизм рендера

Haunted использует шаблоны lit-html для генерации DOM. Когда состояние изменяется через setState, библиотека сравнивает предыдущий и новый результат шаблона, обновляя только изменившиеся узлы. Такой подход минимизирует операции с DOM и повышает производительность.

setCount(count + 1); // триггерит ререндер

Процесс рендера можно разделить на этапы:

  1. Вызов функции компонента — возвращается новый шаблон html.
  2. Сравнение шаблонов — Haunted определяет, какие узлы изменились.
  3. Обновление DOM — изменяются только изменённые части дерева, остальной DOM остаётся неизменным.

Сложные состояния

Для хранения объектов или массивов важно не мутировать данные напрямую, а создавать новые копии. Это позволяет Haunted корректно отслеживать изменения.

const [items, setItems] = useState([]);

function addItem(newItem) {
  setItems([...items, newItem]);
}

Пояснение: Если изменять массив через push, Haunted не заметит изменения, и ререндер не произойдет. Создание нового массива через spread-оператор гарантирует реактивность.


Несколько состояний в компоненте

Компонент может иметь несколько независимых состояний:

const [name, setName] = useState('Иван');
const [age, setAge] = useState(30);

Каждое состояние управляется отдельно. Обновление одного не затрагивает другие, что позволяет более тонко контролировать ререндеры и минимизировать ненужные обновления DOM.


Передача состояния между компонентами

Состояние в Haunted локально для компонента. Для обмена данными между компонентами используют:

  1. События CustomEvent:
this.dispatchEvent(new CustomEvent('update', { detail: count }));
  1. Внешние хранилища (например, с использованием Observables или Redux-подобного паттерна).

События позволяют родительскому компоненту реагировать на изменения состояния дочернего компонента без прямого доступа к его внутренним данным.


Жизненный цикл состояния

Haunted управляет состоянием через hook-based lifecycle:

  • Состояние создается при монтировании компонента.
  • Хуки вызываются в строгом порядке каждый рендер.
  • Очистка возможна через useEffect с возвращаемой функцией:
import { useEffect } from 'haunted';

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

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


Поддержка сложных реактивных структур

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

const [user, setUser] = useState({ name: 'Иван', age: 30 });

setUser({ ...user, age: 31 });

Иммутабельность позволяет библиотеке точно определять, что изменилось, и обновлять только необходимые части DOM.


Основные принципы состояния в Haunted

  1. Локальность — состояние принадлежит только компоненту.
  2. Реактивность — изменение через функцию обновления вызывает ререндер.
  3. Иммутабельность — объекты и массивы должны копироваться при изменении.
  4. Порядок вызова хуков — критичен для корректной работы.
  5. Минимальные изменения DOM — Haunted обновляет только изменившиеся элементы, повышая производительность.

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