Перевод статьи
Контекст React предоставляет данные компонентам независимо от того, насколько глубоко они находятся в дереве компонентов
В этом посте вы узнаете, как использовать концепцию контекста в React.
Оглавление
- 1. Как использовать контекст
- 2. Когда он вам пригодится?
- 3. Пример использования (имя пользователя)
- 3.1 Контекст на помощь
- 3.2 Когда контекст меняется
- 4. Обновление контекста
- 5. Вывод
1. Как использовать контекст
Для использования контекста в React требуется 3 простых шага: создание контекста(A), предоставление контекста(Б) и использование контекста(В).
А. Создадим контекст
Заводская функция принимает один необязательный аргумент: 'Любое значение'
Б. Предоставление контекста
Компонент Context.Provider - доступный в экземпляре контекста, используется для предоставления контекста его дочерним компонентам, независимо от их глубины.
Опять же, здесь важно то, что все компоненты, которые позже захотят использовать контекст, должны быть заключены в компонент провайдера.
В. Использование контекста
Использование контекста может быть выполнено двумя способами. Первый способ - это использовать хук useContext (Context)
Хук также гарантирует повторный рендеринг компонента при изменении значения контекста
Второй способ - использовать функцию рендеринга, предоставленную в качестве дочернего для специального компонента Context.Consumer, доступного в экземпляре контекста:
Вы можете иметь столько дочерних компонентов, сколько хотите для одного контекста. Если значение контекста изменяется (путем изменения свойства value провайдера (<Context.Provider value = {value} />), то все дочерние компоненты немедленно уведомляются и повторно обрабатываются. Если дочерний компонент не заключен внутри провайдера, но все же пытается получить доступ к значению контекста (используя useContext (Context) или <Context.Consumer>), то значение контекста будет аргументом значения по умолчанию, предоставленным createContext (defaultValue) фабричная функция, создавшая контекст.
2. Когда он вам пригодится?
Основная идея использования контекста - предоставить вашим компонентам доступ к некоторым глобальным данным и повторный рендеринг при изменении этих глобальных данных. Контекст решает проблему сверления реквизита: когда вам нужно передать реквизиты от родителей детям.
Вы можете держать внутри контекста:
- Глобальное состояние приложения
- Тема приложения
- Конфигурация приложения
- Аутентификация пользователя
- Пользовательские настройки
- Предпочтительный язык
- Набор услуг
С другой стороны, вы должны хорошо подумать, прежде чем принимать решение об использовании контекста в своем приложении.
- Во-первых, интеграция контекста добавляет сложности. Создание контекста, обертывание всего в провайдере, использование useContext () в каждом дочернем компоненте - это увеличивает сложность.
- Во-вторых, добавление контекста затрудняет модульное тестирование компонентов. Во время модульного тестирования вам придется заключить потребительские компоненты в поставщик контекста. Включая компоненты, на которые косвенно влияет контекст - родителей дочерних компонентов контекста!
3. Пример использования (имя пользователя)
Самый простой способ передать данные от родителя к дочернему компоненту - это когда родитель назначает реквизиты своему дочернему компоненту
Родительский компонент <App /> назначает данные userName своему дочернему компоненту <UserInfo name = {userName} /> с помощью свойства userName.
Это обычный способ передачи данных с использованием реквизита. Вы можете использовать этот подход без проблем. Ситуация меняется, когда дочерний компонент <UserInfo /> не является прямым потомком <Application />, но содержится в нескольких предках. Например, предположим, что компонент <Application /> (тот, у которого есть глобальные данные userName) отображает компонент <Layout />, который, в свою очередь, отображает компонент <Header />, который, в свою очередь, в конечном итоге отображает компонент <UserInfo /> (который хотел бы получить доступ к имени пользователя).
Посмотрим как это будет выглядеть
Вы можете видеть проблему: поскольку компонент <UserInfo /> отображается глубоко в дереве, и все родительские компоненты (<Layout /> и <Header />) должны передавать свойство userName.
Эта проблема также известна как Буровая установка.
Контекст React - возможное решение. Давайте посмотрим, как его применить в следующем разделе.
3.1 Контекст на помощь
Напоминаем, что для применения контекста React требуются 3 участника: контекст, провайдер, извлеченный из контекста, и дочерний компонент.
Во-первых, const UserContext = createContext ('Unknown') создает контекст, в котором будет храниться информация об имени пользователя.
Во-вторых, внутри компонента <App /> дочерние компоненты приложения заключены в контекст пользователя: <UserContext.Provider value = {userName}>. Обратите внимание, что свойство value компонента поставщика важно: именно так вы устанавливаете значение контекста.
Наконец, <UserInfo /> становится потребителем контекста с помощью встроенной ловушки useContext (UserContext). Хук вызывается с контекстом в качестве аргумента и возвращает значение имени пользователя.
Промежуточные компоненты <Layout /> и <Header /> не должны передавать свойство userName. В этом большое преимущество контекста - он снимает бремя передачи данных через промежуточные компоненты.
3.2 Когда контекст меняется
Когда значение контекста изменяется путем изменения свойства значения поставщика контекста (<Context.Provider value = {value} />), тогда все его потребители уведомляются и повторно обрабатываются. Например, если я изменю имя пользователя с «Дэн Абрамов» на «Дэн, Дэн Абрамов», то потребитель <UserInfo /> немедленно выполнит повторный рендеринг, чтобы отобразить последнее значение контекста
4.Обновление контекста
React Context API по умолчанию не имеет состояния и не предоставляет специальный метод для обновления значения контекста из компонентов-потребителей.
Но это можно легко реализовать, интегрировав механизм управления состоянием (например, хуки useState () или useReducer ()) и предоставив функцию обновления прямо в контексте рядом с самим значением. В следующем примере компонент <App /> использует ловушку useState () для управления значением контекста.
<UserNameInput /> потребитель считывает значение контекста, из которого извлекаются userName и setUserName. Затем потребитель может обновить значение контекста, вызвав функцию обновления setUserName (newContextValue)
<UserInfo /> - еще один потребитель контекста. Когда <UserNameInput /> обновляет контекст, этот компонент также обновляется.
Обратите внимание, что <App /> запоминает значение контекста. Мемоизация сохраняет объект значения контекста одним и тем же до тех пор, пока userName остается неизменным, предотвращая повторную визуализацию потребителей каждый раз, когда повторно отображается <App />. В противном случае, без мемоизации, const value = {userName, setUserName} создаст разные экземпляры объекта во время повторного рендеринга <App />, инициируя повторный рендеринг в потребителях контекста.
5. Вывод
Контекст в React - это концепция, которая позволяет вам снабжать дочерние компоненты глобальными данными, независимо от того, насколько глубоко они находятся в дереве компонентов.
Для использования контекста требуется 3 шага: создание, предоставление и использование контекста. При интеграции контекста в ваше приложение учтите, что он значительно усложняет его. Иногда "прокинуть" пропсы через 2-3 уровня иерархии не составляет большой проблемы.
Спасибо Дмитрий Павлютин