В React 16.3 Context API окончательно перестал быть экспериментальным API и стал очень полезной функцией, которую теперь можно безопасно использовать в продакшене. Времена, когда нам приходилось решать, будем ли мы передавать опоры вниз от родителя вниз через несколько компонентов, которые даже не используют опору, или вместо этого использовать Redux, к счастью, остались позади.

Вместо бурения опор теперь мы можем использовать Context API для создания провайдера со значениями, которые мы хотим сделать доступными для дочернего компонента. В дочернем компоненте мы можем просто использовать Consumer для доступа к переданным значениям.

Давайте начнем с простого проекта, чтобы увидеть, как работает Context API. Откройте свой терминал и запустите npm install -g create-response-app, а затем, когда он будет установлен, создайте новое приложение, набрав create-response-app context-api. После создания проекта введите cd context-api, а затем npm start. У вас должна быть возможность получить доступ к приложению React по адресу http: // localhost: 3000 / и увидеть стандартное содержимое приложения React при его создании. Немного очистим файл App.js, так как нам там не особо все нужно. Вот как должен выглядеть ваш файл App.js на данный момент:

import React, { Component } from ‘react’;
import ‘./App.css’;
class App extends Component {
 render() {
   return (
     <div className=”App”>
     </div>
   );
 }
}
export default App;

В каталоге «src» создайте новую папку «components», а затем внутри создайте файл Header.js. В Twitter пользователи могут выбирать свою собственную цветовую схему, поэтому мы создадим простой заголовок, в котором мы предоставим конфигурацию для темы. Сначала добавьте фиктивный контент в файл Header.js, а также создайте файл Header.css с небольшим стилем.

Header.js

import React, { Component } from ‘react’;
import ‘./Header.css’;
const Header = props => {
 return (
   <header className=”orange-theme”>
     <div className=”header-container”>
       <div>Here is our awesome logo</div>
       <nav>
         <ul>
           <li>Home</li>
           <li>About</li>
           <li>Profile</li>
           <li>Help</li>
         </ul>
       </nav>
     </div>
   </header>
 )
}
export default Header;

Header.css

header {
 width: 100%;
 height: 80px;
}
.orange-theme {
 background-color: #FF851B;
}
.teal-theme {
 background-color: #39CCCC;
}
.green-theme {
 background-color: #2ECC40;
}
.header-container {
 display: flex;
 justify-content: space-between;
 align-items: center;
 width: 70%;
 height: 100%;
 margin: 0 auto;
}
nav ul {
 display: flex;
 list-style: none;
}
nav ul li {
 margin: 0 20px;
}

Цвет нашей темы по умолчанию будет оранжевым, но у нас также есть бирюзовая и зеленая темы. Конечно, теперь нам также нужно импортировать Header.js и добавить его в наш компонент приложения.

import React, { Component } from ‘react’;
import ‘./App.css’;
import Header from ‘./components/Header’;
class App extends Component {
 render() {
   return (
     <div className=”App”>
       <Header />
     </div>
   );
 }
}
export default App;

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

Я знаю, ничего особенного, но мы здесь не для того, чтобы создавать красивый заголовок;) Нам нужно создать еще два файла, первый - config.js. Мы поместим туда объект с выбранной пользователем темой. Обычно подобная конфигурация загружается с сервера, но для целей данного руководства этого должно быть достаточно. В config.js просто напишите:

export default {
 userTheme: ‘teal’
}

Второй файл - это ThemeContext.js, в котором мы создадим новый контекст. Создайте для него новую папку в каталоге / src под названием «context», а затем создайте наш файл ThemeContext.js.

Пришло время начать веселье. В ThemeContext.js создайте и экспортируйте новую константу, которая будет содержать контекст и передавать объект со свойством userTheme, которое по умолчанию будет оранжевым, если тема не указана.

import React from ‘react’
export const ThemeContext = React.createContext({userTheme: ‘orange’})

Следующее, что нужно сделать, - это использовать поставщика, чтобы сделать эту тему доступной для дочерних компонентов. В App.js мы должны импортировать контекст, а затем обернуть верхний div с помощью ThemeContext.Provider. Нам также необходимо импортировать наш userConfig и передать его как значение поставщику. Вот как должен выглядеть ваш файл App.js:

import React, { Component } from ‘react’;
import ‘./App.css’;
import Header from ‘./components/Header’;
import userConfig from ‘./config.js’;
import { ThemeContext } from ‘./context/ThemeContext’;
class App extends Component {
 render() {
   return (
     <ThemeContext.Provider value={userConfig}>
       <div className=”App”>
         <Header />
       </div>
     </ThemeContext.Provider >
   );
 }
}
export default App;

Импортируйте ThemeContext в Header.js, чтобы мы могли использовать его для получения пользовательской конфигурации.

import { ThemeContext } from ‘../context/ThemeContext’;
const Header = props => {
 return (
   <ThemeContext.Consumer>
     …other content here
   </ThemeContext.Consumer>
 )
}

Важно помнить, что Consumer требует дочерней функции, возвращающей JSX. Значение, которое мы передали в провайдер, доступно как первый параметр. Мы воспользуемся деструктуризацией, чтобы получить свойство userTheme и использовать его для класса заголовка.

import { ThemeContext } from ‘../context/ThemeContext’;
const Header = props => {
 return (
   <ThemeContext.Consumer>
     {({ userTheme }) => (
       <header className={userTheme + ‘-theme’}>
         …other content here
       </header>
     )}
   </ThemeContext.Consumer>
 )
}

Если вы сохраните файл Header.js, вы должны увидеть, что цвет фона заголовка действительно изменился на бирюзовый. Вот как вы передали значение родительского компонента дочернему. Я знаю, что в этом случае заголовок является прямым потомком приложения, и вы можете просто передать его как опору, но это просто для того, чтобы показать, как работает Context API. Если вы удалите свойство userTheme из конфигурации, то фон изменится на оранжевый, поскольку мы предоставили тему по умолчанию при создании контекста.

Контекстный API - очень интересная и полезная функция, которая может помочь вам избежать передачи свойств через многие компоненты. Были даже предположения, что теперь, когда Context API больше не является экспериментальным, он заменит необходимость в библиотеках управления состоянием, таких как Redux.

Я лично считаю, что библиотеки управления состоянием по-прежнему останутся важной частью приложений React. В отличие от Context API, библиотеки управления состоянием действительно предлагают протестированные решения, которые помогают анализировать и поддерживать поток приложения и то, как компоненты взаимодействуют друг с другом.

Мы можем сохранить наши компоненты более компактными, имея при этом отдельные заботы и централизованное хранилище с государством. А может, давайте просто создадим библиотеку управления состоянием на основе Context API? Мы посмотрим, что нас ждет в будущем, поскольку трудно предсказать, что может произойти при постоянно меняющихся тенденциях и технологиях.