В этом посте мы поговорим о Context API, который был представлен в React 16, и о том, как вы можете их использовать.

Что такое контекст?

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

Другими словами, контекст - это универсальные данные для реагирующего приложения (или, по определению redux, централизованное хранилище вашего реагирующего приложения). Состояние, которое вы установили в контексте, будет доступно в любом месте дерева реакции.

Когда следует использовать контекст?

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

На мой взгляд, Context следует использовать, если вас раздражает необходимость передавать реквизиты более чем на 3 уровня в дереве компонентов и в итоге получается слишком много реквизитов, которые не используются промежуточным компонентом. Итак, здесь Context работает лучше всего, имея состояние, доступное у потребителя.

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

Давайте рассмотрим пример, чтобы увидеть, как работает контекст.

API

React.createContext

Сначала мы создаем новый объект контекста, который описывает, как будут выглядеть данные (мы также можем хранить функции в нашем состоянии).
Все, что мы помещаем в объект контекста, мы хотим использовать в потребительском компоненте.

//NameContext.js
import React from 'react';
const NameContext = React.createContext({
  name: '',
  handleNameChange() {},
});
export const Provider = NameContext.Provider;
export const Consumer = NameContext.Consumer;

createContext предоставит нам 2 компонента Provider и Consumer, которые мы можем использовать в нашем приложении.

Context.Provider

После того, как мы создали наш контекст, мы можем использовать поставщика, но перед этим давайте рассмотрим, что такое компонент Provider и Consumer и как они работают с контекстом.

Представьте, как вы добираетесь из пункта A в пункт B на поезде, вы идете ко входу на станцию ​​и предъявляете билет (Контекст) при прохождении через ворота (Поставщик), чтобы сесть на поезд. Достигнув пункта назначения, вы передаете свой билет (контекст) выходным воротам (Потребителю), чтобы его потребить.

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

//App.js
import React from 'react';
import { render } from 'react-dom';
import { Provider } from './NameContext';
import Child from './Child';
class App extends React.Component {
  constructor(props) {
    super(props);
    this.handleNamechange = this.handleNamechange.bind(this);
    this.state = {
      name: 'Malik',
      handleNameChange: this.handleNamechange,
    };
  }
  handleNamechange(event) {
    let nameValue = event.target.value;
    this.setState(function() {
      return {
        name: nameValue,
      };
    });
  }
  render() {
    return (
      <Provider value={this.state}>
        <h1>Hello</h1>
        <Child />
      </Provider>
    );
  }
}

Обратите внимание, как мы обернули Provider component, который мы импортировали из NameContext, вокруг Child component и передали его value prop с состоянием приложения в качестве значения. Таким образом, все внутри Provider может получить доступ к контексту с помощью Consumer component.

Context.Consumer

После того, как мы обернули компонент Provider вокруг раздела приложения, в котором мы хотим использовать контекст. Компонент-потребитель будет подписываться на изменение контекста с помощью функционального компонента.

Другими словами, чтобы использовать контекст, компоненту потребуется функция в качестве дочернего элемента, которая получит текущее значение контекста в качестве аргумента. Эта функция вернет узел React, который будет отображаться на основе значения контекста.

//Child.js
import React from 'react';
import { Consumer } from './NameContext';
import GrandChild from './GrandChild';
class Child extends React.Component {
  render() {
    return (
      <Consumer>
        {function(context) {
          return (
            <div>
              <h2>{context.name}</h2>
              <input
                onChange={context.handleNameChange}
                value={context.name}
                placeholder="Name"
              />
              <GrandChild />
            </div>
          );
        }}
      </Consumer>
    );
  }
}
export default Child;

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

//GrandChild.js
import React from 'react';
import { Consumer } from './NameContext';
class GrandChild extends React.Component {
  constructor(props) {
    super(props);
    this.handleClick = this.handleClick.bind(this);
  }
  handleClick() {
    console.log(this.props);
  }
  render() {
    return (
      <div>
        <h3>Gabroun</h3>
        <button onClick={this.handleClick}>Submit</button>
      </div>
    );
  }
}
export default function GrandChildWithContext() {
  return (
    <Consumer>
      {function(context) {
        return <GrandChild data={context} />;
      }}
    </Consumer>
  );
}

Вы можете иметь несколько видов контекста, обернув поставщика вокруг другого поставщика для доступа к контексту.

В заключение

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