JS: React
Теория: Хук useContext
React передает данные внутрь компонентов с верхних уровней на нижние, используя пропсы.
Такой подход неудобен при работе с глобальными данными, которые нужны одновременно во многих компонентах на разных уровнях иерархии. К таким данным относится текущий уровень, текущая тема (темная или светлая) и так далее. Напрямую передавать такие данные неудобно, придется протаскивать их сквозь все приложение.
В таких случаях React позволяет передать данные в приложение и получить внутри любого компонента доступ к этим данным напрямую, минуя пропсы. Этот механизм называется контекст.
Хук useContext() позволяет использовать контекст внутри компонента. Для этого нужно выполнить три действия:
-
Инициализировать контекст в том же месте, где инициализируется приложение
-
Подключить провайдер и передать данные в контекст через пропс
value. -
Получить данные контекста
Вот другой пример контекста, в котором хранится текущая тема:
И где-то внутри приложения:
Метод React.createContext() принимает значение по умолчанию. Это значение будет передаваться в контекст тех компонентов, которые не обернуты в провайдер. Обычно провайдер всегда используется, чтобы оборачивать все приложение. Поэтому компоненты всегда принимают в контексте значение, переданное провайдером. Но если мы работаем с компонентом вне провайдера, может понадобиться такое значение по умолчанию. Например, такая ситуация может сложиться при тестировании компонента отдельно от приложения.
Внутри контекста может храниться как примитивное значение, так и объект. Изменение содержимого такого объекта никак не отслеживается React, поэтому не приводит к перерендеру. Но если заменить сам объект, то из-за изменившейся ссылки React узнает об изменении и выполнит перерисовку компонентов внутри провайдера.
Иногда возникает ситуация, когда в контексте нужно хранить динамические данные. Например, при авторизации. Когда пользователь авторизован, мы должны сохранить какие-то данные, чтобы пользователю предоставлялись дополнительные функции. Сам по себе контекст для этого ничего не предоставляет, но можно передать в контекст методы для манипулирования данными, а сами данные хранить с помощью useState(). Более продвинутый вариант — это создать провайдер в отдельном компоненте. Так мы сможем изолировать данные от всего приложения, а в компоненты передавать интерфейс для взаимодействия с данными.
Для этого создадим контекст в отдельном модуле, чтобы все компоненты могли его импортировать:
Создаем отдельный компонент провайдера:
И внутри приложения используем провайдер как обычный компонент:
В самом компоненте теперь можно импортировать контекст и использовать функции из провайдера для изменения состояния в контексте:
Не забываем встроить приложение на страницу:
Контекст - удобный механизм для некоторых особых ситуаций, но он не должен становиться основным способом передачи данных внутрь приложения. Такой соблазн появляется у многих, кто использует его впервые. Главная проблема контекстов — связывание компонентов с глобальными данными, а это затрудняет их повторное использование в других ситуациях.




