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 уместен для глобальных данных (тема, пользователь, язык), а не вместо обычных пропсов.