Включите исполнение JavaScript в браузере, чтобы запустить приложение.
31 мар 2025

React Context: что это и как использовать

React Context — это способ передать данные через дерево компонентов в приложениях Реакт. В обзоре ниже расскажем, как создать контекст, для чего он нужен, что дает, как использовать Provider (провайдера) и Consumer (консьюмера).

Зачем нужна React Context и когда используется

В библиотеке React используются разные способы передачи данных между компонентами приложения:

  • props/пропсы (properties);
  • The Context (React Context API);
  • React-Redux/Redux и иные State Manager-ы.

У каждого способа есть плюсы и минусы. Ниже разберем, с чем возникают сложности и почему.

Проблема проп-вординга и решение через контекст

Программисты в Реакт работают с деревом компонентов. Основной способ — прокидывать пропсы «от родителя к ребенку» (from Parent to Child). К примеру, есть дерево:

Пример дерева компонентов в Реакт
Пример дерева компонентов в Реакт

Нам нужно передать to Child — нижнему компоненту — свойства (theme — цветовую тему, lang — язык или любые другие в соответствии с логикой приложения). На изображении этот компонент отмечен фиолетовым.

Компонент в Реакт, которому нужны пропсы
Компонент в Реакт, которому нужны пропсы

Чтобы пропс был получен, его должен передать родитель. Например, наш component получил props (к примеру, theme) от родителя и изменил цвет. И здесь видна первая проблема props. Нашу theme получает и второй дочерний компонент, хотя ему не нужны данные проперти. А подобных компонентов «внизу дерева» может быть 100 или 200. Получается, они засоряются пропсами, которые не используются.

Передача пропсов от родителя к детям
Передача пропсов от родителя к детям

Но есть и еще один нюанс. Что делать, если от нижнего цветного блока нужно передать theme соседнему (с которым наш блок не связан отношениями from Parent to Child)? 

Передача пропсов соседнему компоненту
Передача пропсов соседнему компоненту

Передать theme в пропсах соседу не получится. Придется поднять их с нижнего центрального блока на верхнего родителя (to Parent) и от него уже спустить нужному компоненту (to Child). 

Механизм передачи пропертис соседнему компоненту через родителя
Механизм передачи пропертис соседнему компоненту через родителя

Чтобы передать одно свойство, нам пришлось задействовать половину дерева. При этом нужны пропсы и theme были всего лишь одному компоненту. Сами же пропсы могут быть достаточно «тяжелыми» — например, выбранный язык, UI-тема (theme).

Это можно сравнить с ситуацией, когда в компании не налажены горизонтальные связи между отделами. Например, редактору нужно, чтобы дизайнеры писали во всех материалах GitVerse. Вместо того, чтобы пойти напрямую в соседний отдел с дизайнерами и сказать: «С сегодняшнего дня мы пишем GitVerse, а не The GITVERSE во всех маркетинговых материалах», редактору приходится подниматься к руководителю отдела контента, ему — к заместителю директора, заместителю — к гендиректору, гендиректору — к руководителю отдела дизайна, руководителю отдела дизайна — к дизайнеру UX/UI. Было бы здорово придумать механизм, чтобы передача данных осуществлялась без проблемы «проброса по уровням». Так и появился React Context.

Преимущества использования React Context

React Context API — интерфейс, позволяющий сохранить переменную или объект и использовать ее несколькими компонентами, не имеющими связи «родитель–ребенок» (from Parent to Child). Контекст же (контекстный стор) — это и есть та сохраненная величина. 

Интерфейс react-контекста включает: 

  • компонент Context.Provider c value;
  • метод createContext();
  • хук useContext(). 

В React Context есть:

  • провайдер (Provider — тот, кто передает контекст и value);
  • получатель (Consumer — тот, кто получает контекст).

При таком подходе пропадают «лишние звенья», которые использовались только для передачи пропсов и нужных value на уровень выше. Появляются только Provider и Consumer (from Provider to Consumer).

Как устроен Provider-Consumer в React
Как устроен Provider-Consumer в React

Создание контекста в React: начальный этап

Пошаговая инструкция, что нужно сделать для создания Provider, контекста и потребителя:

  1. Создать контекст через createContext(). Сделать это можно как в файле провайдера, так и в отдельном файле (но потом импортировать в Provider).
  2. Обернуть родительский компонент, чтобы все дочерние имели доступ к контексту (to store). Вложенные в провайдера компоненты могут получить контекстный стор.
  3. Создать дочерние компоненты. Они будут потребителями. Для доступа к стору используется хук useContext (или обертка <ComponentContext.Consumer> </ComponentContext.Consumer>).

Писать код можно в среде разработки GIGA IDE Desktop или GIGA IDE Cloud. Умный AI-ассистент объяснит или задокументирует код и возьмет на себя часть рутинных задач разработчика.

GigaCode в GigaIDE Desktop объясняет код
GigaCode в GigaIDE Desktop объясняет код

Чтобы все заработало, создаем проект и файлы в папке src:

  • main.tsx — точка входа, где будет отрисовываться компонент GitVerseApp;
  • GitVerseContex.jsx — стор (контекст);
  • GitVerseApp.jsx — Provider и его value;
  • GitVerseChildComponent.jsx — дочерний компонент.

Структура проекта выглядит таким образом:

Структура проекта в IDE
Структура проекта в IDE

Использование метода createContext

В файле GitVerseContex.jsx объявляем Context.

Код в файле GitVerseContex.jsx (названия проектов и переменных разработчик может задавать самостоятельно) выглядит таким образом:

import { createContext } from 'react';
const GitVerseContex = createContext();
export default GitVerseContex;
javascript
Создание контекста (стора)
Создание контекста (стора)

Определение провайдера и потребителей контекста

Далее необходимо создать провайдера контекста. Им оборачивают все те компоненты, которые будут использовать глобальные переменные стора.

Объявляем Provider и называем его — например, GitVerseAppProvider.jsx. Код:

import './App.css';
import GitVerseContex from './GitVerseContex';
const GitVerseAppProvider = () => (
  <GitVerseContex.Provider value="GitVerseParentPage">
    <h1>Ура, вместе с Gitverse создали провайдера!</h1>
  </GitVerseContex.Provider>
);
export default GitVerseAppProvider;
javascript
Создание провайдера
Создание провайдера

Создаем дочерний компонент GitVerseChildComponent.jsx, который делает return простой фразы. Код:

import { useContext } from 'react';
import GitVerseContex from './GitVerseContex';
const GitVerseChildComponent = () => {
  const GitVersepageName = useContext(GitVerseContex);
  return <p>Это дочерний компонент для the page {GitVersepageName}</p>;
};
export default GitVerseChildComponent;
javascript
Создание дочернего компонента, у которого будет доступ к стору при помощи useContext
Создание дочернего компонента, у которого будет доступ к стору при помощи useContext

Код с return пока не будет работать, ведь мы его не подключили. Необходимо перейти в GitVerseAppProvider и отрисовать в нем дочерний компонент. Код:

import './App.css';
import GitVerseContex from './GitVerseContex';
import GitVerseChildComponent from './GitVerseChildComponent';
const GitVerseAppProvider = () => (
  <GitVerseContex.Provider value="GitVerseParentPage">
    <h1>Ура, вместе с Gitverse создали провайдера!</h1>
    <GitVerseChildComponent />
  </GitVerseContex.Provider>
);
export default GitVerseAppProvider;
javascript
Подключение дочернего компонента
Подключение дочернего компонента

Пока контекстный стор пуст. Можно перейти в файл GitVerseContex и вывести в консоль содержимое GitVerseContex.

Добавляем console.log(GitVerseContex):

Вывод store в консоль
Вывод store в консоль

В результате можно убедиться, что объект действительно существует (список value ниже):

Результат вывода стора в консоль
Результат вывода стора в консоль

Стор нужно наполнить данными (theme, языковая версия, геолокация и другие в зависимости от логики приложения).

React Context API: как использовать контекст в приложениях

The React Context API — тема, которую на самом деле разработчики редко используют «как есть». Необходимо понимать, как работает контекст. Но для написания кода давно созданы специальные библиотеки, которые делают всю логику The React Context «под капотом». Например, Redux с его flux-подходом. На смену Редаксу пришли библиотеки Mobx и Zustand. Сегодня используют фреймворк The TanStack (поддерживает не только React, но и Solid, Vue, Angular, Svelte).

Применение хука useContext для доступа к данным

useContext — это hook (хук), который позволяет подписаться на контекст и считывать с него данные. С помощью useContext можно делать кастомные хуки.

Синтаксис:

const value = useContext(GitVerseThemeContext);
javascript

Пример кода с хуком для работы с UI-темой (the theme):

import { useContext } from 'react';
function GitVerseComponent() {
    const theme = useContext(GitVerseThemeContext);
  }
javascript

Управление глобальным состоянием с React Context и useState

useState — это вебхук, который позволяет добавить в компонент переменную состояния.

Синтаксис:

const [state, setState] = useState(initialState);
javascript

Пример кода с использованием useState для управления состоянием:

import { useState } from 'react';
function GitVerseComponent() {
    const [id, setId] = useState(183);
    const [projectName, setName] = useState('GigaCode');
    const [tasks, setTasks] = useState(() => createTasks());
   }
javascript

GigaCode объяснит, как работает useState в написанном выше коде:

GigaCode объясняет работу веб-хука useState
GigaCode объясняет работу веб-хука useState

Еще с помощью GigaCode можно создать более сложную функцию, в которой будет использовать useContext и useState, а затем возвращать (return) component:

GigaCode пишет функцию для счетчика с использованием веб-хука useState
GigaCode пишет функцию для счетчика с использованием веб-хука useState
GigaCode пишет счетчик с использованием веб-хука useContext, которая делает return кнопки с обработчиком
GigaCode пишет счетчик с использованием веб-хука useContext, которая делает return кнопки с обработчиком
GigaCode объясняет, как обернуть component Провайдером для доступа всех дочерних к стору
GigaCode объясняет, как обернуть component Провайдером для доступа всех дочерних к стору

Работа с контекстом на классовых компонентах

При работе с классовыми components (для тех, кто пишет на классах) код будет выглядеть иначе. Пошаговая инструкция — ниже.

Создать контекст:

const GitVerseContext = React.createContext(defaultValue);
javascript

Создать провайдера и передать в него value:

<GitVerseContext.Provider value={theme}>
javascript

Объявить Class.contextType и использовать методы классов (не забывать использовать this):

class GitVerseClass extends React.Component {
    componentDidMount() {
        let value = this.context;
         }
    componentDidUpdate() {
        let value = this.context;
      }
    componentWillUnmount() {
        let value = this.context;
       }
    render() {
        let value = this.context;
          }
}
GitVerseClass.contextType = GitVerseContext;
javascript

Назначить потребителя:

<GitVerseContext.Consumer>

  {value => 'Здесь рендерится что-то с использованием контекста — the theme, value и т.д.'}

</GitVerseContext.Consumer>
javascript

Классовые компоненты с this считаются легаси-кодом. Но на отдельных проектах их по-прежнему можно встретить. С хуками все проще: достаточно использовать веб-хук useContext, чтобы получить доступ к стору. Не нужно оборачивать компонент в <ComponentContext.Consumer></ComponentContext.Consumer>.

Оптимизация производительности при использовании React Context

Частая проблема, которая бьет по производительности, — ререндеры компонентов (даже при использовании memo и useMemo). Как улучшить производительность?

Лучшие практики для эффективного использования контекста

  1. Значение, которое передается Провайдером в value, — это всегда новый объект, даже если обернуть функции в useCallback. Для оптимизации нужно их мемоизировать.
  2. Сами функции создают новые ссылки в памяти, и их также необходимо мемоизировать.
  3. При использовании useCallback массив зависимостей целесообразно оставлять пустым. Значение передаются через стрелочную функцию как параметр.
  4. При передаче value в Provider необходимо отделить значения и функции. Это позволит избежать перерендера.
  5. ReactContext не стоит использовать для хранения локального состояния.
  6. Контекст может стать причиной так называемого «Context Hell» с большим количеством values («елочка», «лестница»). В таких случаях целесообразно использовать State Managers или хотя бы писать хелперы.
  7. ReactContext нецелесообразно использовать, если нужно пробросить данные буквально на один-два уровня.

React Context vs Redux: когда выбирать контекст для управления состоянием

Redux — это библиотека для управления состоянием (стейт менеджер). Условно говоря, может быть ситуация, когда в зависимости проекта устанавливается library весом как 3 Реакта. Но при этом разработчики используют только 5–10% ее функциональности. Естественно, в таком случае возникает вопрос эффективности. 

Но в случае с глобальным стором целесообразно использовать придуманное и протестированное решение — Redux. 

Критерий сравненияThe React ContextThe Redux
Что такоеСпособ передавать данные через дерево без необходимости пробрасывать их через уровни (официальная документация)Паттерн проектирования и библиотека для управления, состоянием приложения
Основные составляющиеThe Provider (поставщик), The Consumer (получатель), The Context (стор)Store, Actions (объекты для инициирования изменений) и Reducers (функции, отвечающие за обновления). Дополнительно появляютсяMiddleware (промежуточный слой) и некоторые другие.
Работа с side effectsОтвечает только за рендерингРаботает с побочными эффектами
Для каких ситуаций подходитНужно прокинуть небольшую UI-тему, языковую версию и т.д. Подходят для пет-проектов и изучения, как работает Redux под капотомКрупные проекты, где нужно много глобального стейта
Нет удобной интеграции с асинхронными actions (нужно писать самостоятельно) через useEffect. Можно попробовать писать экшены самостоятельно
Отслеживание, почему и как обновлятся приложениеСложно. Нет четкой структуры action: разделения на reducers, заранее созданных экшенов и так далее. Логика может быть размазана по всему приложениюПроще 
Возможность асинхронного обновленияЗатруднительны асинхронные обновления компонентовВозможны асинхронные обновления компонентов

Примеры использования React Context в реальных проектах

The ReactContext можно сравнить со своего рода «тоннелем» (pipe), через который прокидываются данные. Это не полноценный инструмент управления состоянием по сравнению с библиотеками и стейт-менеджерами. Его основное предназначение — избавиться от Props drilling, проблемы прокидывания пропсов и value между соседними компонентами. 

Основные кейсы использования The ReactContext:

  • тема/theme (переключение между светлым и темным режимами);
  • регион и геолокация пользователя;
  • иные данные, которые не требуют сложной логики и частого обновления.

Подводные камни и ограничения React Context

ReactContext запускает повторный рендеринг, и для устранения этой проблемы приходится использовать мемоизацию (которая помогает не всегда).