Создание контекста

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


Создание контекста

Для создания контекста используется функция createContext. Она возвращает объект с двумя свойствами: Provider и Consumer.

import { createContext } from 'haunted';

const ThemeContext = createContext('light'); // 'light' — значение по умолчанию

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

  • Значение по умолчанию используется только в случае, если компонент не находится внутри Provider.
  • Контекст может содержать любой тип данных: примитивы, объекты, функции.

Провайдер контекста

Provider оборачивает компоненты и передает им значение через контекст. Его основной проп — value.

import { html, component } from 'haunted';

const App = () => html`
  <${ThemeContext.Provider} .value=${'dark'}>
    <theme-display></theme-display>
  <//>
`;

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

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

  • Изменение value вызывает реактивное обновление всех потребляющих компонентов.
  • Provider можно вкладывать друг в друга, создавая локальные области действия контекста.

Потребление контекста

Для получения значения контекста используется хук useContext.

import { useContext } from 'haunted';

const ThemeDisplay = () => {
  const theme = useContext(ThemeContext);
  return html`Текущая тема: ${theme}`;
};

customElements.define('theme-display', component(ThemeDisplay));

Важные моменты:

  • useContext должен вызываться только внутри компонента, созданного с помощью component.
  • Любое изменение значения в Provider автоматически обновляет все компоненты, использующие useContext.

Контекст и реактивность

Контекст в Haunted полностью интегрирован с системой реактивности библиотеки. Если значение в Provider изменяется динамически, все потребляющие компоненты обновляются без необходимости вручную подписываться на события.

const ThemeSwitcher = () => {
  const [theme, setTheme] = useState('light');

  return html`
    <${ThemeContext.Provider} .value=${theme}>
      <theme-display></theme-display>
      <button @click=${() => setTheme(theme === 'light' ? 'dark' : 'light')}>
        Переключить тему
      </button>
    <//>
  `;
};

customElements.define('theme-switcher', component(ThemeSwitcher));

Особенности динамических изменений:

  • useState работает совместно с Provider для реактивного обновления контекста.
  • Можно комбинировать несколько контекстов для передачи различных состояний одновременно.

Локальный и глобальный контекст

Haunted позволяет создавать несколько уровней контекста. Вложенные Provider переопределяют значение только для своей области:

const Outer = () => html`
  <${ThemeContext.Provider} .value=${'blue'}>
    <Inner></Inner>
  <//>
`;

const Inner = () => html`
  <${ThemeContext.Provider} .value=${'red'}>
    <theme-display></theme-display>
  <//>
`;
  • В этом примере компонент theme-display внутри Inner получит значение 'red', а компоненты вне Inner'blue'.
  • Такой подход позволяет создавать изолированные области состояния, не влияя на глобальный контекст.

Контекст с функциями и объектами

Контекст удобно использовать для передачи не только данных, но и функций:

const CounterContext = createContext({ count: 0, increment: () => {} });

const CounterProvider = () => {
  const [count, setCount] = useState(0);

  const contextValue = {
    count,
    increment: () => setCount(count + 1),
  };

  return html`
    <${CounterContext.Provider} .value=${contextValue}>
      <counter-display></counter-display>
    <//>
  `;
};

const CounterDisplay = () => {
  const { count, increment } = useContext(CounterContext);
  return html`
    <div>Счётчик: ${count}</div>
    <button @click=${increment}>Увеличить</button>
  `;
};

Выводы по объектам и функциям:

  • Можно передавать сложные объекты состояния с методами.
  • Компоненты автоматически реагируют на изменения значений внутри объекта, если используется useState или useReducer.

Передача контекста через Shadow DOM

Контексты в Haunted работают через Shadow DOM. Это значит, что контекст проходит через компоненты с Shadow DOM, не требуя каких-либо дополнительных механизмов:

customElements.define('shadow-wrapper', component(() => html`
  <div>
    <slot></slot>
  </div>
`));
  • Компоненты внутри <shadow-wrapper> смогут использовать useContext без проблем.
  • Нет необходимости прокидывать контекст вручную через свойства или слоты.

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