useContext

Хук useContext предоставляет способ читать данные из React-контекста без необходимости прокидывать пропсы через каждый уровень компонентного дерева. Это особенно полезно для глобальных данных, таких как тема приложения, язык интерфейса или информация о текущем пользователе.

Как работает контекст

Контекст состоит из двух частей:

  1. Провайдер (Provider) — компонент, который передаёт значение вниз по дереву.
  2. Потребитель (Consumer) — любой компонент, который получает это значение с помощью useContext.

Сначала создаётся контекст:

import { createContext } from 'react';

const ThemeContext = createContext('light'); // 'light' — значение по умолчанию

Затем обёртываем часть приложения в провайдер:

<ThemeContext.Provider value="dark">
  <App />
</ThemeContext.Provider>

Внутри любого дочернего компонента можно получить значение:

import { useContext } from 'react';

function Button() {
  const theme = useContext(ThemeContext);
  return <button className={theme}>Кнопка</button>;
}

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

useContext уместен, когда:

  • Данные нужны во многих компонентах на разных уровнях вложенности.
  • Изменение данных должно вызывать перерисовку всех зависимых компонентов.
  • Прокидывание пропсов становится громоздким («пропс-дриллинг»).

Типичные сценарии:

  • Темизация
  • Мультиязычность
  • Аутентификация
  • Глобальные настройки

Важные ограничения

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

  • Храните в контексте только связанные данные (не объединяйте всё в один глобальный объект).
  • Разбивайте контексты по смыслу: AuthContext, ThemeContext, LanguageContext.
  • Для сложных значений используйте useMemo, чтобы сохранять ссылочную стабильность.

Пример плохой практики:

// Не делайте так
<GlobalContext.Provider value={{ user, theme, lang, settings }}>

Лучше:

<UserContext.Provider value={user}>
<ThemeContext.Provider value={theme}>

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

Значение по умолчанию

Значение по умолчанию (передаваемое в createContext) используется только если компонент не находится внутри соответствующего Provider. Оно не подходит для динамической инициализации — например, из localStorage. В таких случаях лучше управлять состоянием выше и передавать его в Provider.


Примечание: useContext не заменяет все остальные хуки. Он решает конкретную проблему — передачу данных «сквозь» дерево. Для локального состояния по-прежнему используйте useState или useReducer.