Context API: обзор
Context API — встроенный механизм React для передачи данных через дерево компонентов без явной передачи пропсов на каждом уровне (без props drilling).
Зачем нужно
Когда несколько компонентов на разных уровнях дерева нуждаются в одних данных (текущий пользователь, тема, язык), передавать их через props на каждом уровне громоздко. Context создаёт «глобальное» хранилище в рамках поддерева, которое любой потребитель читает напрямую. Это встроенное решение — без сторонних библиотек — подходит для средне-сложного состояния; для сложного state management рассматривают Redux или Zustand.
Где используется
- Тема приложения (светлая/тёмная):
ThemeContext - Авторизация:
AuthContextс текущим пользователем - Локализация: выбранный язык и функция перевода
- Корзина покупок в небольшом e-commerce SPA
Как работает Context API
import { createContext, useContext, useState } from 'react';
// 1. Создание контекста с дефолтным значением
const ThemeContext = createContext('light');
// 2. Provider — оборачивает поддерево и передаёт значение
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>
);
}
// 3. Consumer через useContext — читает текущее значение
function ThemedButton({ children }) {
const { theme, toggleTheme } = useContext(ThemeContext);
return (
<button
style={{
background: theme === 'light' ? '#fff' : '#333',
color: theme === 'light' ? '#333' : '#fff',
}}
onClick={toggleTheme}
>
{children}
</button>
);
}
// 4. Использование в приложении
function App() {
return (
<ThemeProvider>
<header>
<ThemedButton>Переключить тему</ThemedButton>
</header>
<main>
{/* Любой вложенный компонент может использовать useContext(ThemeContext) */}
</main>
</ThemeProvider>
);
}
Паттерн: кастомный хук для контекста
// Лучшая практика — скрыть useContext за кастомным хуком
function useTheme() {
const context = useContext(ThemeContext);
if (!context) {
throw new Error('useTheme должен использоваться внутри ThemeProvider');
}
return context;
}
// Теперь компоненты используют:
const { theme } = useTheme;
// вместо:
const { theme } = useContext(ThemeContext);
Context vs Props vs Redux
Пропсы → для 1-2 уровней, локальные данные
Context API → для 3+ уровней, данные всего поддерева (тема, auth)
Redux/Zustand → сложный state с действиями, middleware, DevTools
Частые ошибки
- Лишние ре-рендеры — каждый потребитель
useContextперерендеривается при изменении любой части значения контекста; разделяйте контексты по смыслу (отдельно для данных, отдельно для экшенов). - Мутация значения контекста напрямую — нужно всегда вызывать setState-функцию, а не изменять объект.
- Используют Context для часто меняющихся данных — например, позиция курсора или анимации вызовут лавину ре-рендеров; для таких случаев лучше refs или специализированные библиотеки.
Связанные темы
- _MOC SPA
- Props Drilling -- проблема
- Локальное vs глобальное состояние
- State -- внутреннее состояние
- Redux -- концепции и архитектура