← Назад к вопросам

Зачем нужна библиотека React Context?

2.0 Middle🔥 271 комментариев
#React#Архитектура и паттерны

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

React Context - управление глобальным состоянием

React Context — это встроенное в React API для передачи данных между компонентами без необходимости пробрасывать props на каждом уровне вложенности. Это решает проблему "prop drilling" (бурления пропсов) в больших приложениях.

Основная проблема, которую решает Context

Prop drilling (бурление пропсов):

// Плохо: нужно пробросить theme через 5 уровней компонентов
<App>
  <Layout theme="dark">
    <Sidebar theme="dark">
      <Menu theme="dark">
        <MenuItem theme="dark" />
      </Menu>
    </Sidebar>
  </Layout>
</App>

С Context это решается:

// Хорошо: компоненты могут напрямую получить значение
<ThemeProvider value="dark">
  <App />
</ThemeProvider>

Как работает Context

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

import { createContext } from 'react';

const ThemeContext = createContext('light');

Provider - предоставляет значение:

export function ThemeProvider({ children, value }) {
  return (
    <ThemeContext.Provider value={value}>
      {children}
    </ThemeContext.Provider>
  );
}

Потребитель значения через useContext:

import { useContext } from 'react';

function Button() {
  const theme = useContext(ThemeContext);
  return (
    <button className={`button-${theme}`}>
      Нажми меня
    </button>
  );
}

Практический пример: приложение с темой

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

import { createContext, useState } from 'react';

const ThemeContext = createContext();

export function ThemeProvider({ children }) {
  const [theme, setTheme] = useState('light');

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

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

export function useTheme() {
  const context = useContext(ThemeContext);
  if (!context) {
    throw new Error('useTheme должен быть использован внутри ThemeProvider');
  }
  return context;
}

Использование в приложении:

import { useTheme } from './ThemeContext';

function Header() {
  const { theme, toggleTheme } = useTheme();

  return (
    <header className={`header-${theme}`}>
      <button onClick={toggleTheme}>
        Переключить на {theme === 'light' ? 'тёмную' : 'светлую'} тему
      </button>
    </header>
  );
}

function App() {
  return (
    <ThemeProvider>
      <Header />
      <main>Содержимое</main>
    </ThemeProvider>
  );
}

Несколько Context'ов вместе

Комбинирование нескольких провайдеров:

function App() {
  return (
    <ThemeProvider>
      <LanguageProvider>
        <AuthProvider>
          <MainApp />
        </AuthProvider>
      </LanguageProvider>
    </ThemeProvider>
  );
}

// Или с помощью compose функции
function combineProviders(...providers) {
  return ({ children }) => 
    providers.reduceRight((child, Provider) => 
      <Provider>{child}</Provider>, 
      children
    );
}

const AppProviders = combineProviders(
  ThemeProvider,
  LanguageProvider,
  AuthProvider
);

function App() {
  return (
    <AppProviders>
      <MainApp />
    </AppProviders>
  );
}

Когда использовать Context

Хорошие примеры:

  1. Аутентификация (текущий пользователь, токен)
  2. Тема приложения (светлая/тёмная)
  3. Язык интерфейса (локализация)
  4. Модальные окна и уведомления
  5. Глобальные настройки приложения

Плохие примеры:

  1. Часто меняющееся состояние (leads to re-renders)
  2. Большие объемы данных
  3. Состояние, которое меняется на каждый render
  4. Простые данные для одного компонента

Context vs Redux vs Zustand

ХарактеристикаContextReduxZustand
Встроен в ReactДаНетНет
СложностьПростойСложныйОчень простой
ПроизводительностьХорошаяОтличнаяОтличная
DevToolsНетДаДа
Асинхронные операцииНужны хукиMiddlewareПросто
Размер бандла0 КБ+60 КБ+2 КБ

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

Проблема: лишние re-renders

// Плохо: весь компонент перерендерится
function App() {
  const [theme, setTheme] = useState('light');
  const [notifications, setNotifications] = useState([]);

  return (
    <ThemeContext.Provider value={{ theme, setTheme }}>
      <NotificationsContext.Provider value={{ notifications, setNotifications }}>
        <Header />
      </NotificationsContext.Provider>
    </ThemeContext.Provider>
  );
}

Решение: разделить контексты

// Хорошо: каждый контекст отдельный
<ThemeProvider>
  <NotificationsProvider>
    <Header />
  </NotificationsProvider>
</ThemeProvider>

Использование useMemo для оптимизации:

function ThemeProvider({ children }) {
  const [theme, setTheme] = useState('light');

  const value = useMemo(() => ({ theme, setTheme }), [theme]);

  return (
    <ThemeContext.Provider value={value}>
      {children}
    </ThemeContext.Provider>
  );
}

Основные преимущества

  1. Избегаем prop drilling — не нужно пробрасывать пропсы через много уровней
  2. Чистый код — компоненты не знают о внутренней структуре
  3. Переиспользуемость — контекст можно использовать в разных местах приложения
  4. Встроено в React — не нужна дополнительная библиотека
  5. Простота — легко начать использовать

Основные ограничения

  1. Производительность — при частых обновлениях переренды все потребители
  2. Нет DevTools — сложнее дебажить
  3. Нет middleware — сложнее обрабатывать асинхронные операции
  4. Дублирование кода — нужна своя обработка состояния

Лучшие практики

  1. Используй кастомный хук (useTheme) для доступа к контексту
  2. Раздели контексты по доменам (Auth, Theme, Language)
  3. Оборачивай контекст в Provider компонент
  4. Используй useMemo для оптимизации
  5. Помни о производительности при частых изменениях
Зачем нужна библиотека React Context? | PrepBro