Prop drilling и Context

Избавляемся от «проп-дриллинга» — прокидывания пропсов через десяток компонентов — с помощью Context.

Context — механизм React для передачи данных любому компоненту в поддереве напрямую, минуя промежуточные пропсы.

Боль: prop drilling

Prop drilling — это когда данные нужны глубоко вложенному компоненту, и их приходится «протаскивать» через все промежуточные, которым они вообще не нужны:

// theme нужна только глубоко внутри, но тащим её через всех
<App>
  <Layout theme={theme}>
    <Sidebar theme={theme}>
      <Menu theme={theme}>
        <Button theme={theme} /> {/* вот здесь она реально нужна */}
</...>

Промежуточные компоненты вынуждены принимать и передавать theme просто как транзит. Код раздувается, рефакторить тяжело.

Решение в три шага

Context создаёт «общий канал»: один компонент кладёт в него значение, любой потомок — забирает.

Шаг 1: создать контекст

import { createContext } from "react";

export const ThemeContext = createContext("light");

Шаг 2: предоставить значение через Provider

Оборачиваем поддерево в Provider и задаём значение. Все потомки внутри получат к нему доступ:

function App() {
  const [theme, setTheme] = useState("dark");
  return (
    <ThemeContext.Provider value={theme}>
      <Layout />  {/* больше не передаём theme пропсом */}
    </ThemeContext.Provider>
  );
}

Шаг 3: прочитать через useContext

Глубоко вложенный компонент читает значение хуком useContext — напрямую, без цепочки пропсов:

import { useContext } from "react";
import { ThemeContext } from "./ThemeContext";

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

Промежуточные Layout, Sidebar, Menu о theme ничего не знают — дриллинг исчез.

Передаём и функции

В контекст можно положить объект — например, значение и функцию его смены, чтобы потомки могли не только читать, но и менять:

<ThemeContext.Provider value={{ theme, setTheme }}>
  <Layout />
</ThemeContext.Provider>

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

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

Итог

  • Prop drilling — прокидывание пропсов через компоненты, которым они не нужны; это утомительно и хрупко.
  • Context (createContext + Provider + useContext) передаёт данные потомкам напрямую.
  • Context уместен для глобальных данных (тема, пользователь, язык), а не вместо обычных пропсов.
Проверьте себя
1. Что такое prop drilling?
AПередача данных через сервер
BПрокидывание пропсов через промежуточные компоненты, которым они не нужны
CОшибка в массиве зависимостей
DСоздание глобальной переменной
2. Каким хуком компонент читает значение из Context?
AuseState
BuseContext
CuseEffect
DuseRef
3. Для каких данных лучше всего подходит Context?
AДля любых пропсов между соседними компонентами
BДля глобальных данных: тема, текущий пользователь, язык
CДля локального состояния поля ввода
DТолько для чисел
Поддержать проект