Контекст
Обычно данные идут от родителя к ребёнку через пропсы. Но если значение нужно компоненту на пятом уровне вложенности, его приходится протаскивать через все промежуточные — это называют «пробрасыванием пропсов». Контекст решает задачу иначе: значение становится доступно любому компоненту внутри обёртки, на любой глубине.
Создание контекста
Добавим в блог переключатель светлой и тёмной темы. Контекст создают один раз в отдельном файле — src/ThemeContext.js:
// src/ThemeContext.js
import { createContext } from 'react';
export const ThemeContext = createContext('light');Аргумент createContext — значение по умолчанию. Его получит компонент, у которого над ним нет обёртки.
Передача значения
Сам контекст служит компонентом-обёрткой. Значение задают пропом value, обычно в src/App.jsx:
// src/App.jsx
import { ThemeContext } from './ThemeContext.js';
import PostList from './components/PostList.jsx';
export default function App() {
return (
<ThemeContext value="dark">
<PostList />
</ThemeContext>
);
}В React 19 контекст пишут как тег напрямую. В старых версиях обёртка выглядела как ThemeContext.Provider — такой код ещё встречается и тоже работает.
Чтение значения
Любой компонент внутри получает значение хуком useContext. Создайте src/components/ThemedBox.jsx:
// src/components/ThemedBox.jsx
import { useContext } from 'react';
import { ThemeContext } from '../ThemeContext.js';
export default function ThemedBox({ children }) {
const theme = useContext(ThemeContext);
return <div className={`box box-${theme}`}>{children}</div>;
}Если обернуть в ThemedBox карточку статьи где-то внутри PostList, у неё появится класс box-dark. Промежуточным компонентам о теме знать не нужно.
Контекст с состоянием
Чтобы тему можно было переключать, в контекст кладут состояние вместе с функцией изменения:
// src/App.jsx
import { useState } from 'react';
export default function App() {
const [theme, setTheme] = useState('light');
return (
<ThemeContext value={{ theme, setTheme }}>
<ThemeSwitch />
<PostList />
</ThemeContext>
);
}// src/components/ThemeSwitch.jsx
import { useContext } from 'react';
import { ThemeContext } from '../ThemeContext.js';
export default function ThemeSwitch() {
const { theme, setTheme } = useContext(ThemeContext);
return (
<button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>
Тема: {theme}
</button>
);
}Кнопка переключает тему, и все компоненты, читающие контекст, перерисовываются с новым значением. Теперь useContext возвращает объект, поэтому в ThemedBox пишите const { theme } = useContext(ThemeContext).
Когда использовать
Контекст подходит для данных, нужных во многих местах: тема, язык интерфейса, текущий пользователь. Для данных одного-двух компонентов хватит пропсов — с ними проще понять, откуда пришло значение.
Частая ошибка
Компонент, который читает контекст вне обёртки, молча получит значение по умолчанию:
export default function App() {
return (
<>
<ThemeContext value="dark">
<PostList />
</ThemeContext>
<Footer /> {/* здесь тема будет 'light' */}
</>
);
}Убедитесь, что обёртка охватывает все компоненты, которым нужно значение. Часто её ставят на самый верх — в src/main.jsx или в корень App.