Разбираемся в React Context

Разбираемся в React Context

От автора: в последнее время вы, возможно, задумывались над тем, что React Context у всех на слуху и что это может означать для вас и ваших сайтов на React. До Context, когда управление состоянием становилось сложнее, чем позволял сделать функционал setState, вам, вероятно, приходилось использовать стороннюю библиотеку. Благодаря недавним обновлениям команды Awesome React, у нас теперь есть Context, который может помочь в решении некоторых проблем управления состоянием.

Что решает Context?

Как передать состояние из родительского компонента в дочерний, который вложен в дерево компонентов? Вы знаете, что мы можем использовать Redux для управления состоянием, но вам не обязательно прибегать к Redux в каждой ситуации.

Есть способ сделать это без использования Redux или любого другого стороннего инструмента управления состоянием. Вы можете использовать свойство! Скажем, функция, которую вы хотите реализовать, имеет древовидную структуру, похожую на эту:

Состояние находится в компоненте App и требуется для компонентов UserProfile и UserDetails. Вам нужно передать его через свойство вниз по дереву. Если компоненты, которые нуждаются в этом состоянии, имеют глубину до 10 уровней, это может быть сложно, утомительно и чревато ошибками. Каждый компонент должен быть как черный ящик — другие компоненты не должны знать о состояниях, которые им не нужны. Ниже приведен пример приложения, которое соответствует приведенному выше сценарию.

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

Context приходит на помощь!

Context API React позволяет сохранять состояние в том, что выглядит как глобальное состояние приложения и доступ к нему осуществляется только в тех компонентах, которые в нем нуждаются, без необходимости передавать его через свойства. Мы начинаем с инициализации нового Context с использованием createContext():

Этот новый Context присваивается переменной const, в данном случае это переменная UserContext. Вы видите, что нам нет необходимости устанавливать библиотеку, когда createContext() доступен в React (16.3.0 и выше).

Компонент Provider делает Context доступным для компонентов, которые в нем нуждаются — они называются Subscribers. Другими словами, компонент Provider позволяет Consumers подписываться на изменения в Context. Помните, что Context похож на глобальное состояние приложения. Таким образом, компоненты, которые не являются Consumers, не будут подписаны на контекст. Если вы кодируете локально, ваш файл контекста будет выглядеть так:

Provider

Мы будем использовать Provider в родительском компоненте, где у содержится наше состояние.

Provider принимает значение, которое будет передано его дочерним Consumer-компонентам. В этом случае мы передадим пользовательское состояние компонентам Consumer. Вы видите, что мы не передаем состояние компоненту User в качестве свойства. Это означает, что мы можем редактировать компонент User и исключать свойства, так как они ему не нужны:

Consumer

Несколько компонентов могут подписаться на один компонент Provider. Наш компонент UserProfile должен использовать контекст, поэтому он будет подписан на него.

Затем данные, которые мы ввели в Provider через значение свойства, будут доступны через параметры контекста функции. Теперь мы можем использовать имя пользователя этого пользователя в нашем компоненте.

Компонент UserDetails будет похож на компонент UserProfile, поскольку он является подписчиком одного и того же компонента Provider:

Обновление состояния

Но что делать, если мы хотим предоставить пользователям возможность изменять свои имя и фамилию? Это также возможно. Компоненты Consumer могут повторно отображаться каждый раз, когда происходят изменения в значении, передаваемом компонентом Provider. Давайте рассмотрим пример.

В компоненте Consumer у нас будет два поля ввода для имени и фамилии. Из компонента Provider мы будем получать два метода, которые обновляют состояние приложения, используя значения, введенные в поля ввода. Достаточно разговоров, давайте напишем код! Наш компонент приложения будет выглядеть так:

Мы передаем объект, который содержит состояние и действия, в значения свойств, которые получает Provider. Действия — это методы, которые будут запускаться при возникновении события onChange. Затем значение события используется для обновления состояния. Поскольку мы хотим обновить либо имя, либо фамилию, необходимо сохранить значение обоих. Для этого мы используем ES6 Spread Operator, который позволяет нам обновить значение указанного ключа. Теперь нам нужно соответствующим образом обновить компонент UserProfile.

Мы используем деструктурирование ES6 для извлечения состояния из значения, полученного от Provider. Для компонента UserDetails мы извлекаем и состояние, и действия. Нам также нужно добавить два поля ввода, которые будут прослушивать событие onChange() и вызвать соответствующие методы.

Использование значений по умолчанию

При инициализации Context можно передавать значения по умолчанию. Чтобы сделать это, вместо передачи пустого объекта createContext() мы передадим некоторые данные.

Чтобы использовать эти данные в дереве приложений, нам нужно удалить провайдер из дерева. Таким образом, наш компонент приложения будет выглядеть так.

Данные, которые будут использоваться в компонентах Consumer, будут определены при инициализации нового Context.

В заключение

Когда все усложняется, и у вас возникает желание запустить yarn install [<insert third-party library for state management], сделайте паузу на секунду — у вас есть React Context.

Автор: Kingsley Silas

Источник: //css-tricks.com/

Редакция: Команда webformyself.

Метки:

Похожие статьи:

Комментарии Вконтакте: