Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

Контекст

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

Создание контекста

Добавим в блог переключатель светлой и тёмной темы. Контекст создают один раз в отдельном файле — 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.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.