Provider Pattern в Haunted упрощает передачу данных через иерархию
веб-компонентов без промежуточных свойств и событий. Механизм основан на
использовании контекста (context) и декораторов provide и
consume. Такой подход усиливает композиционность
компонентов и снижает связанность.
Контекст Контекст описывает канал передачи значения.
Он создаётся функцией createContext(). Созданный объект
контекста используется как ключ для связывания поставщика (provider) и
потребителей (consumers).
Provider Поставщик публикует значение в контекст. Это может быть состояние компонента, конфигурация приложения, сервис или любая другая модель.
Consumer Потребитель подписывается на изменения значения контекста и реагирует на них как на локальное состояние.
Контекст объявляется один раз и используется в любом количестве компонентов.
import { createContext } from 'haunted';
export const themeContext = createContext();
Контекст не хранит значение самостоятельно, а служит дескриптором связи.
Провайдер часто реализуется как компонент, обладающий собственным
состоянием. Публикация значения выполняется декоратором
provide.
import { component, useState, provide } from 'haunted';
import { html } from 'lit-html';
import { themeContext } from './theme-context.js';
function ThemeProvider() {
const [theme, setTheme] = useState('light');
provide(themeContext, theme);
return html`
<slot></slot>
`;
}
customElements.define('theme-provider', component(ThemeProvider));
Ключевой момент: провайдер передаёт контекст вниз по дереву DOM до ближайших потребителей.
Потребитель получает значение контекста через декоратор
consume. Значение обновляется при каждом изменении
контекста.
import { component, consume } from 'haunted';
import { html } from 'lit-html';
import { themeContext } from './theme-context.js';
function ThemeSwitcher() {
const theme = consume(themeContext);
return html`
<div>Текущая тема: ${theme}</div>
`;
}
customElements.define('theme-switcher', component(ThemeSwitcher));
Provider Pattern важен при работе со сложными моделями, реактивными сторы или API-клиентами. Пример: публикация объекта вместо строки.
const userContext = createContext();
function UserProvider() {
const [user, setUser] = useState({ name: 'Alice', role: 'admin' });
provide(userContext, user);
return html`<slot></slot>`;
}
Потребители получают и используют объект как локальное состояние, избавляясь от необходимости явно передавать свойства.
Контексты работают по принципу поиска ближайшего провайдера вверх по дереву. Это позволяет переопределять значения на любом уровне: общий провайдер задаёт настройки приложения, а вложенный компонент локально меняет их для дочерних элементов.
<theme-provider theme="light">
<theme-provider theme="dark">
<theme-switcher></theme-switcher>
</theme-provider>
</theme-provider>
В примере потребитель получит dark, так как ближайший
провайдер перекрывает вышестоящий.
Provider Pattern устраняет необходимость пробрасывать колбеки и состояния через промежуточные компоненты. Компоненты, которые не используют данные, не знают о контексте и не зависят от него, что повышает переиспользуемость.
Контексты корректно работают вместе с useState,
useReducer, useMemo и другими хуками Haunted.
Обновление стейта провайдера вызывает реакцию потребителей без
дополнительных действий.
Provider Pattern хорошо ложится на архитектуру, вдохновлённую React. Возможно внедрение глобальных сторах (например, Redux, Zustand, Jotai), сервисов или адаптеров API. Контекст скрывает реализацию стора и раскрывает только интерфейс данных.
Распространение значения Контекст не использует DOM-события, а полагается на внутренний механизм подписок. Это означает предсказуемые обновления без ручного подписывания.
Неконтролируемые области Контексты ограничиваются субдеревом DOM. При переносе элементов с помощью порталов или теневых DOM-границ необходимо учитывать, что провайдер может не достигать таких компонентов.
Низкая связанность компонентов Потребители зависят только от контекста, а не от конкретного провайдера.
Повышенная модульность Легкое замещение провайдера позволяет создавать тестовые окружения, переопределять настройки и адаптировать приложение под различные сценарии.
Минимизация проп-дриллинга Поскольку данные не передаются по цепочке свойств, уменьшается объем кода и вероятность ошибок.
Провайдеры могут подменяться при тестировании, что позволяет изолировать поведение потребителей. Вместо сложных моков достаточно предоставить контекст с тестовыми значениями.
<theme-provider .theme=${'test-theme'}>
<theme-switcher></theme-switcher>
</theme-provider>
Такой подход упрощает тестирование и демонстрирует строгие зависимости.
Темизация интерфейса Публикация информации о теме, цветовых схемах и шрифтах.
Глобальные модели Пользовательские сессии, конфигурация приложения, данные локализации.
Сервисы и API-клиенты Инициализация REST-клиентов, WebSocket-подписок, кэширования.
Состояния приложения Хранилища с глобальным состоянием, включая флаги и настройки взаимодействия.
Использование Provider Pattern в Haunted даёт веб-компонентам средства для построения сложных интерфейсов с изолированными уровнями состояния и конфигурации, сохраняя простоту и читаемость кода.