JS: React
2026-02-26 23:19 Diff

React передает данные внутрь компонентов с верхних уровней на нижние, используя пропсы.

Такой подход неудобен при работе с глобальными данными, которые нужны одновременно во многих компонентах на разных уровнях иерархии. К таким данным относится текущий уровень, текущая тема (темная или светлая) и так далее. Напрямую передавать такие данные неудобно, придется протаскивать их сквозь все приложение.

В таких случаях React позволяет передать данные в приложение и получить внутри любого компонента доступ к этим данным напрямую, минуя пропсы. Этот механизм называется контекст.

Хук useContext() позволяет использовать контекст внутри компонента. Для этого нужно выполнить три действия:

  1. Инициализировать контекст в том же месте, где инициализируется приложение

  2. Подключить провайдер и передать данные в контекст через пропс value.

  3. Получить данные контекста

Вот другой пример контекста, в котором хранится текущая тема:

И где-то внутри приложения:

Метод React.createContext() принимает значение по умолчанию. Это значение будет передаваться в контекст тех компонентов, которые не обернуты в провайдер. Обычно провайдер всегда используется, чтобы оборачивать все приложение. Поэтому компоненты всегда принимают в контексте значение, переданное провайдером. Но если мы работаем с компонентом вне провайдера, может понадобиться такое значение по умолчанию. Например, такая ситуация может сложиться при тестировании компонента отдельно от приложения.

Внутри контекста может храниться как примитивное значение, так и объект. Изменение содержимого такого объекта никак не отслеживается React, поэтому не приводит к перерендеру. Но если заменить сам объект, то из-за изменившейся ссылки React узнает об изменении и выполнит перерисовку компонентов внутри провайдера.

Иногда возникает ситуация, когда в контексте нужно хранить динамические данные. Например, при авторизации. Когда пользователь авторизован, мы должны сохранить какие-то данные, чтобы пользователю предоставлялись дополнительные функции. Сам по себе контекст для этого ничего не предоставляет, но можно передать в контекст методы для манипулирования данными, а сами данные хранить с помощью useState(). Более продвинутый вариант — это создать провайдер в отдельном компоненте. Так мы сможем изолировать данные от всего приложения, а в компоненты передавать интерфейс для взаимодействия с данными.

Для этого создадим контекст в отдельном модуле, чтобы все компоненты могли его импортировать:

Создаем отдельный компонент провайдера:

И внутри приложения используем провайдер как обычный компонент:

В самом компоненте теперь можно импортировать контекст и использовать функции из провайдера для изменения состояния в контексте:

Не забываем встроить приложение на страницу:

Контекст - удобный механизм для некоторых особых ситуаций, но он не должен становиться основным способом передачи данных внутрь приложения. Такой соблазн появляется у многих, кто использует его впервые. Главная проблема контекстов — связывание компонентов с глобальными данными, а это затрудняет их повторное использование в других ситуациях.