Диспатч действий

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


Использование dispatch и кастомных событий

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

Пример базового диспатча:

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

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

  const increment = () => {
    const event = new CustomEvent('increment', {
      detail: { value: count + 1 },
      bubbles: true,
      composed: true
    });
    dispatchEvent(event);
  };

  return html`
    <div>
      <p>Счётчик: ${count}</p>
      <button @click=${increment}>Увеличить</button>
    </div>
  `;
}

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

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

  • CustomEvent позволяет передать данные через detail.
  • bubbles: true и composed: true обеспечивают, что событие поднимется через DOM-иерархию, позволяя родительскому компоненту его обработать.
  • Функция dispatchEvent вызывается на текущем элементе (this), что делает компонент автономным и независимым.

Обработка диспатч событий в родителях

Родительские компоненты могут слушать события и обновлять состояние или выполнять другие действия. Это особенно важно при использовании Haunted для создания приложений с несколькими связанными компонентами.

import { html, component, useState } from 'haunted';
import './counter.js';

function App() {
  const [total, setTotal] = useState(0);

  const handleIncrement = (event) => {
    setTotal(event.detail.value);
  };

  return html`
    <div @increment=${handleIncrement}>
      <my-counter></my-counter>
      <p>Общее значение: ${total}</p>
    </div>
  `;
}

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

Особенности подхода:

  • События из дочерних компонентов не требуют прямого доступа к внутреннему состоянию.
  • Логика обработки состояния остаётся в родителе, что соответствует принципам разделения ответственности.
  • Любой компонент может подписываться на одно и то же событие, позволяя строить сложные реактивные цепочки.

Комбинация с хуками Haunted

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

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

function Logger() {
  const [logs, setLogs] = useState([]);

  useEffect(() => {
    const logEvent = (e) => setLogs(prev => [...prev, e.detail.value]);
    window.addEventListener('increment', logEvent);

    return () => window.removeEventListener('increment', logEvent);
  }, []);

  return html`
    <ul>
      ${logs.map(log => html`<li>${log}</li>`)}
    </ul>
  `;
}

customElements.define('event-logger', component(Logger));
  • useEffect позволяет подписываться и отписываться от событий автоматически.
  • События можно слушать глобально или на определённом контейнере.
  • Этот подход подходит для логирования, аналитики и межкомпонентного взаимодействия.

Передача данных через диспатч

Важно понимать, что detail кастомного события — это едиственный безопасный способ передавать данные между компонентами в Haunted. Любые попытки напрямую менять состояние родителя нарушают инкапсуляцию.

const event = new CustomEvent('update-user', {
  detail: { name: 'Alice', age: 25 },
  bubbles: true,
  composed: true
});
this.dispatchEvent(event);
  • Передача объекта через detail позволяет содержать структурированную информацию.
  • События можно фильтровать по типу, что упрощает обработку множества разных действий в одном компоненте.

Стратегии для масштабных приложений

  1. Централизованный менеджер событий Использовать один контейнер, который собирает и распределяет события от всех дочерних компонентов. Это помогает поддерживать единое состояние приложения без глобального хранилища.

  2. Именованные события Присваивать событиям уникальные имена (increment-user, delete-item), чтобы избежать конфликтов и случайного перехвата.

  3. Композиция компонентов Диспатч действий позволяет строить сложные компоненты из более мелких, при этом не теряя контроля над состоянием и не создавая жёстких связей между компонентами.


Взаимодействие с другими библиотеками состояния

Haunted можно использовать совместно с Redux, MobX или Zustand. В таком случае dispatch может быть обёрнут в вызовы экшенов:

const increment = () => {
  store.dispatch({ type: 'INCREMENT', payload: count + 1 });
};
  • Комбинация с хуками Haunted позволяет интегрировать глобальное состояние с реактивными обновлениями.
  • Кастомные события остаются удобным механизмом для локальных событий компонентов, не загружая глобальный стор.

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