Совместное использование состояния с помощью React's Context API
Глобальное состояние в React является синонимом таких библиотек, как Redux. Если вам когда-либо приходилось делить состояние, например текущий маршрут или данные из API, с несколькими компонентами, то вы, возможно, использовали Redux.
Более новые версии React (16.3+) включают встроенный способ совместного использования состояния, что означает отсутствие необходимости извлекать внешнюю библиотеку. Это известно как React Context API, и его может быть немного сложно понять. Я надеюсь предоставить упрощенное объяснение и учебное пособие, чтобы вы могли быстро добавить глобальное состояние в любое из ваших приложений на React.
Проблема, которую мы пытаемся решить
Прежде чем я углублюсь в Context API, позвольте мне сначала описать проблемный сценарий.
Допустим, у нас есть панель инструментов, где пользователь может обновить свое имя пользователя. Имя пользователя отображается по всей панели инструментов, что означает, что имя пользователя будет сохранено в состоянии компонента, а затем передано другим компонентам через props.
Без Context API мы бы сделали что-то вроде этого:
class Dashboard extends React.Component { state = { username: '' }; render() { return (); } }{ this.setState({ username: newUsername }); }} />
Имя пользователя сохраняется в состоянии компонента Dashboard, а затем передается с помощью username в оба компонента
Трудно увидеть какие-либо проблемы с этим прямо сейчас. Подумайте, что может произойти, когда мы добавим на панель инструментов больше компонентов, которые глубоко вложены.
Need to show username here...
В этом примере я пытаюсь показать, что
Hello {this.props.username}!
Это может стать чрезвычайно утомительным, так как мы добавляем больше состояний и вложенных компонентов. Кроме того, есть шанс, что нам нужно получить доступ к имени пользователя за пределами панели мониторинга.
Как использовать Context API
Решением этой проблемы является использование встроенного React Context API.
Это позволяет вам избежать подробного пробрасывания параметров, что означает, что в нашем предыдущем примере компонент
Примечание: полностью рабочий пример доступен на CodeSandbox.
Создание поставщиков и потребительских компонентов
Давайте начнем с создания файла для вашего контекста. Я назову это user-context.js.
В этот файл добавьте следующее:
import React, { createContext } from 'react'; const UserContext = createContext({ username: '', updateUsername: () => {}, }); export class UserProvider extends React.Component { updateUsername = newUsername => { this.setState({ username: newUsername }); }; state = { username: 'user', updateUsername: this.updateUsername, }; render() { return ({this.props.children} ); } } export const UserConsumer = UserContext.Consumer;
Давайте разберем этот файл.
Сначала пользовательский контекст создается с использованием createContext(). Здесь значения будут переопределены UserProvider.
Затем мы создаем компонент UserProvider, который будет служить родительским компонентом для хранения и управления общим состоянием. Думайте об этом как о эквиваленте компонента
Наконец, мы экспортируем компонент UserConsumer, который позволит компонентам получить доступ к общему состоянию.
Использование провайдера
Компонент
import React from 'react'; import ReactDOM from 'react-dom'; import UserMessage from './UserMessage'; import SettingsForm from './SettingsForm'; import { UserProvider } from './user-context'; function App() { return (); } const rootElement = document.getElementById('root'); ReactDOM.render( , rootElement);
Мы также импортируем два других компонента: UserMessage и SettingsForm. Эти два компонента будут иметь доступ к общему состоянию пользователя.
Использование потребителя для чтения состояния
Одним из вариантов использования общего состояния является его отображение. В этом случае мы отобразим текущее имя пользователя. Создайте файл с именем UserMessage.js и добавьте в него следующее:
import React from 'react'; import { UserConsumer } from './user-context'; export default function UserMessage() { return ({({ username }) => ); }Welcome {username}!
}
В этом файле мы создали компонент UserMessage, который отображает сообщение «Welcome username». Имя пользователя извлекается из компонента UserConsumer, который экспортируется из user-context.js.
Внутри
Использование потребителя для обновления состояния
Другой вариант использования общего состояния - обновить его. В этом случае мы предоставим пользователю форму для обновления своего имени пользователя. Создайте файл с именем UserSettings.js и добавьте в него следующее:
import React from 'react'; import { UserConsumer } from './user-context'; export default function UserSettings() { return ({({ updateUsername }) => ( ); })}Settings
{ updateUsername(event.target.value); }} />
Это похоже на предыдущий пример, за исключением того, что вместо получения имени пользователя мы используем функцию updateUsername для его обновления.
В итоге
Если вы запутались в этом вопросе, я настоятельно рекомендую вам посмотреть на работающий пример CodeSandbox, который объединяет все.
Кроме того, вот краткий обзор основных понятий:
- Компонент провайдера оборачивает все приложение для управления общим состоянием.
- Потребительский компонент используется для доступа или обновления общего состояния.
- Файл user-context.js экспортирует оба этих компонента, и общее состояние сохраняется в компоненте
. - Компоненты
и считывают и обновляют общее состояние, просто импортируя и используя компонент . - Вы можете читать и обмениваться информацией о состоянии из любого места в вашем приложении, предполагая, что
оборачивает все ваше приложение.
Вот и все. Не стесняйтесь использовать эту функцию, чтобы поделиться состоянием для навигации, модальных окон или даже данных. Сила в твоих руках 💪