Создание и использование контекста

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


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

Для создания контекста используется функция createContext из пакета preact:

import { createContext } from 'preact';

const ThemeContext = createContext('light');

Здесь 'light' — значение по умолчанию, которое будет использоваться, если компонент-потребитель не обернут в Provider. Контекст можно назвать любым образом, исходя из его предназначения: UserContext, AuthContext, SettingsContext и т.д.


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

Провайдер (Provider) является компонентом, предоставляющим значение контекста всем дочерним компонентам:

import { h } from 'preact';
import { useState } from 'preact/hooks';

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

  return (
    <ThemeContext.Provider value={{ theme, setTheme }}>
      <Toolbar />
    </ThemeContext.Provider>
  );
}

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

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

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

Для использования контекста в функциональных компонентах применяется хук useContext:

import { useContext } from 'preact/hooks';

function Toolbar() {
  const { theme, setTheme } = useContext(ThemeContext);

  return (
    <div className={`toolbar toolbar-${theme}`}>
      <button onCl ick={() => setTheme(theme === 'dark' ? 'light' : 'dark')}>
        Переключить тему
      </button>
    </div>
  );
}

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

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

Контекст и оптимизация производительности

Чрезмерное использование контекста может вызвать лишние рендеры компонентов. Для оптимизации рекомендуется:

  1. Разделять контексты по областям применения. Например, не объединять глобальные настройки и локальное состояние в один контекст.
  2. Мемоизация значений. Если value передаётся как объект, использовать useMemo:
import { useMemo } from 'preact/hooks';

function App() {
  const [theme, setTheme] = useState('dark');
  const value = useMemo(() => ({ theme, setTheme }), [theme]);

  return (
    <ThemeContext.Provider value={value}>
      <Toolbar />
    </ThemeContext.Provider>
  );
}
  1. Минимизировать глубину дерева компонентов, где контекст используется, если это возможно.

Контекст в классовых компонентах

В Preact классовые компоненты также могут использовать контекст через статическое свойство contextType:

import { Component } from 'preact';

class Toolbar extends Component {
  render() {
    const { theme, setTheme } = this.context;

    return (
      <div className={`toolbar toolbar-${theme}`}>
        <button onCl ick={() => setTheme(theme === 'dark' ? 'light' : 'dark')}>
          Переключить тему
        </button>
      </div>
    );
  }
}

Toolbar.contextType = ThemeContext;
  • Классовый компонент получает текущее значение контекста через this.context.
  • Такой подход позволяет избежать использования дополнительных функций и хуков.

Вложенные провайдеры

Контекст в Preact поддерживает вложенность. Значение контекста определяется ближайшим провайдером сверху по дереву компонентов:

<ThemeContext.Provider value={{ theme: 'light' }}>
  <Toolbar />
  <ThemeContext.Provider value={{ theme: 'dark' }}>
    <Sidebar />
  </ThemeContext.Provider>
</ThemeContext.Provider>
  • Toolbar получит theme: 'light', а Sidebartheme: 'dark'.
  • Это удобно для локальной переопределяемости глобальных настроек.

Совмещение нескольких контекстов

Для передачи нескольких независимых данных часто создают отдельные контексты:

<UserContext.Provider value={user}>
  <ThemeContext.Provider value={{ theme, setTheme }}>
    <Dashboard />
  </ThemeContext.Provider>
</UserContext.Provider>

В компоненте можно использовать несколько useContext:

const user = useContext(UserContext);
const { theme } = useContext(ThemeContext);

Такой подход повышает читаемость кода и упрощает тестирование.


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