Context API в Preact

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

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

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

import { createContext } from 'preact';

const ThemeContext = createContext('light');

Параметр 'light' — это значение по умолчанию, которое будет использоваться, если компонент не находится внутри Provider.

Provider

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

import { h } from 'preact';
import { ThemeContext } from './ThemeContext';

const App = () => (
  <ThemeContext.Provider value="dark">
    <Header />
    <Content />
  </ThemeContext.Provider>
);

Здесь все компоненты внутри Provider смогут получить значение 'dark'. Provider может быть вложенным, и внутренний Provider перекрывает значение внешнего.

Consumer

Consumer позволяет подписаться на контекст и использовать его значение внутри компонента.

import { h } from 'preact';
import { ThemeContext } from './ThemeContext';

const Header = () => (
  <ThemeContext.Consumer>
    {theme => <h1 className={theme}>Заголовок</h1>}
  </ThemeContext.Consumer>
);

Функция внутри Consumer получает текущее значение контекста и возвращает JSX.

Использование с хуком useContext

В Preact X и выше рекомендуется использовать хук useContext, который упрощает доступ к контексту:

import { h } from 'preact';
import { useContext } from 'preact/hooks';
import { ThemeContext } from './ThemeContext';

const Header = () => {
  const theme = useContext(ThemeContext);
  return <h1 className={theme}>Заголовок</h1>;
};

useContext делает компонент более компактным и читаемым по сравнению с использованием Consumer.

Обновление контекста

Значение контекста может быть динамическим и обновляться с помощью состояния:

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

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

  const toggleTheme = () => {
    setTheme(prev => (prev === 'light' ? 'dark' : 'light'));
  };

  return (
    <ThemeContext.Provider value={theme}>
      <button onCl ick={toggleTheme}>Переключить тему</button>
      <Header />
    </ThemeContext.Provider>
  );
};

Все компоненты, использующие контекст через useContext или Consumer, автоматически перерисуются при изменении значения.

Контекст и производительность

Использование контекста облегчает передачу данных, но может повлиять на производительность при частых изменениях:

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

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

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

const AuthContext = createContext({
  user: null,
  login: () => {},
  logout: () => {}
});

const App = () => {
  const [user, setUser] = useState(null);

  const login = name => setUser({ name });
  const logout = () => setUser(null);

  return (
    <AuthContext.Provider value={{ user, login, logout }}>
      <Profile />
    </AuthContext.Provider>
  );
};

Компоненты внутри AuthContext могут вызывать login и logout напрямую, а также получать текущее состояние пользователя.

Ограничения Context API

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

Context API в Preact — мощный инструмент для организации глобальных данных и их передачи через компоненты без необходимости пробрасывать пропсы на каждом уровне. Правильное использование Provider, Consumer и useContext позволяет создавать чистую и легко поддерживаемую архитектуру приложения.