Контекст для состояния

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

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

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

import { createContext } from 'haunted';

const ThemeContext = createContext('light');
  • Аргумент функции — это значение по умолчанию для контекста. Оно будет использоваться, если компонент находится вне Provider.
  • ThemeContext.Provider позволяет задать значение контекста для вложенных компонентов.
  • ThemeContext.Consumer используется для получения значения контекста внутри компонентов, если не применяется хук useContext.

Использование Provider

Provider создаёт область видимости для контекста и задаёт значение, доступное всем вложенным компонентам.

import { html, component } from 'haunted';

function App() {
  return html`
    <${ThemeContext.Provider} .value=${'dark'}>
      <ChildComponent></ChildComponent>
    <//>
  `;
}

function ChildComponent() {
  return html`<p>Контекст применяется здесь</p>`;
}
  • Атрибут .value определяет текущее значение контекста.
  • Все компоненты внутри Provider получают доступ к значению контекста автоматически.

Получение контекста через useContext

Haunted предоставляет хук useContext для функциональных компонентов, который упрощает работу с контекстом.

import { useContext } from 'haunted';

function ChildComponent() {
  const theme = useContext(ThemeContext);
  return html`<p>Текущая тема: ${theme}</p>`;
}
  • Хук useContext автоматически подписывается на изменения контекста.
  • Любое изменение значения в Provider вызовет повторный рендер компонента, использующего useContext.

Динамическое обновление контекста

Контекст не является статическим. Его значение можно менять динамически, что позволяет создавать реактивные интерфейсы.

import { useState } from 'haunted';

function App() {
  const [theme, setTheme] = useState('light');

  return html`
    <${ThemeContext.Provider} .value=${theme}>
      <ChildComponent></ChildComponent>
      <button @click=${() => setTheme(theme === 'light' ? 'dark' : 'light')}>
        Переключить тему
      </button>
    <//>
  `;
}
  • Изменение состояния theme автоматически обновляет все компоненты, использующие контекст.
  • Такой подход устраняет необходимость пробрасывать пропсы через несколько уровней компонентов.

Вложенные контексты

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

function NestedProviderExample() {
  return html`
    <${ThemeContext.Provider} .value=${'light'}>
      <ChildComponent></ChildComponent>
      <${ThemeContext.Provider} .value=${'dark'}>
        <NestedChild></NestedChild>
      <//>
    <//>
  `;
}
  • ChildComponent получит значение 'light'.
  • NestedChild получит значение 'dark'.

Контекст и мемоизация

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

import { useMemo, useState } from 'haunted';

function App() {
  const [count, setCount] = useState(0);
  const contextValue = useMemo(() => ({ count }), [count]);

  return html`
    <${ThemeContext.Provider} .value=${contextValue}>
      <ChildComponent></ChildComponent>
      <button @click=${() => setCount(count + 1)}>Увеличить</button>
    <//>
  `;
}
  • useMemo предотвращает создание нового объекта при каждом рендере.
  • Это уменьшает количество повторных рендеров дочерних компонентов, использующих контекст.

Ограничения контекста

  • Контекст в Haunted работает только с компонентами, созданными через Haunted (component и html).
  • Контекст не предназначен для глобального состояния между несвязанными деревьями компонентов.
  • Изменение примитивных значений (строк, чисел) проще, чем объектов, так как объекты требуют мемоизации для оптимизации.

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