JS: React
Теория: Контекст (Context API)
Передача данных через пропсы вниз по иерархии компонентов — это немного многословный, но простой механизм. Всегда видно, откуда пришли данные и как они попали внутрь, а компоненты легко переиспользовать, так как они зависят только от входных данных. Но бывают ситуации, когда передача пропсов не вписывается в то, как работает код.
Возьмем для примера текущего пользователя. Часто данные пользователя нужны одновременно в разных частях страницы, причем в очень глубоких компонентах. Для этого придется передавать пользователя буквально по всей иерархии: даже там, где он не нужен компоненту. Единственная цель такой передачи — прокинуть данные до места назначения, пройдя по пути все промежуточные компоненты. Получается, что множество компонентов никак не используют пользователя, они просто передают их дальше по цепочке. В нашей ситуации данные пользователя глобальные. Они нужны сразу многим компонентам на разных уровнях иерархии. Для таких задач в React существует обходной путь.
Context API — механизм, позволяющий сделать глобальные данные доступными из любого компонента напрямую, без прокидывания пропсов. Его использование сводится к трем шагам:
-
Создание контекста:
-
Передача данных в контекст. Работает так: оборачиваем нужные компоненты в компонент контекста
<UserContext.Provider>и передаем туда нужные данные в пропvalue: -
Получение данных из контекста. В компоненте, где нужны данные, нужно указать тип контекста с помощью статического свойства
contextType. Реакт ищет ближайший провайдер этого контекста и берет из него значение. Поиск провайдера происходит вверх по дереву компонентов. Значение контекста будет доступно вthis.context:
https://codepen.io/hexlet/pen/abYVNZR
Еще один пример, где несколько компонентов используют данные из контекста:
https://codepen.io/hexlet/pen/ZExaWVm
В отличие от пропсов, изменение данных в контексте не приводит к перерисовке по умолчанию. Идеально, когда данные в контексте используются только для чтения. Изменяемые данные лучше хранить внутри состояния компонентов. Однако, если очень нужно, то реагировать на изменение контекста возможно, об этом подробнее можно прочитать в документации. В прикладном коде такая возможность используется редко, но на ней основаны разнообразные библиотеки.
Рассмотрим пример, когда контекст используется совместно с изменяемыми данными. Для этого расширим наш пример, добавив больше компаний и переключение между ними:
Разберем пример:
- Мы создали контекст
CompanyContext, который хранит информацию о нескольких компаниях, текущую выбранную компанию и функцию для изменения компании. - В компоненте
<App/>определено состояние с текущей компанией и метод для её изменения. - Компоненты
<CompanyNameComponent/>и<CompanyAddressComponent/>получают данные из контекста и отображают название и адрес текущей компании. <CompanySwitcher/>позволяет переключать между компаниями, обновляя состояние и тем самым меняя отображаемые данные на странице.
При изменении данных в контексте компоненты, которые зависят от этих данных, будут перерисованы. Это происходит благодаря тому, что состояние, хранящее данные контекста, изменяется в компоненте-родителе (<App/>), и новое значение контекста передается вниз через провайдер. Это удобно для таких задач, где изменение состояния напрямую влияет на всё приложение (например переключение темы, языка, пользователя и тд).




