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

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

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

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

Итак, вернемся к что такое контекст? Контекст позволяет передавать данные состояния от родителя к потомку в дереве компонентов через Provider. У каждого дочернего компонента может быть Потребитель, который будет подписываться на изменения состояния родительского компонента. Теперь это круто. Функциональный дочерний компонент может подписаться на состояние родителя.

Чем полезен контекст?

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

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

Простой учебник

Где уже пример? Не волнуйтесь. Это будет дальше!

Создайте контекст. Давайте создадим файл Context.js. Он создаст для нас Провайдера и Потребителя.

import { createContext } from "react"
const { Provider, Consumer } = createContext()
export { Provider, Consumer }

Во-первых, нам нужно импортировать createContext из response. Это позволит нам создать наш объект Context. Затем мы создадим Provider и Consumer. Это важно. Провайдер предоставит (без каламбура… ну, вроде как) состояние Потребителя. Каждый Потребитель будет подписываться на обновления от Поставщика.

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

import React, { Component } from "react"
import { Provider } from "./Context"
import Child from "./Child"
class Parent extends Component {
  state = {
    people: [
      { id: 0, name: "Bob", age: 24 },
      { id: 1, name: "Jack", age: 22 },
      { id: 2, name: "Jill", age: 26 },
    ],
  }
  render() {
    return (
      <Provider value={this.state}>
        <Child />
      </Provider>
    )
  }
}
export default Parent

состояние объявлено как люди. У людей есть три предмета. Затем объект контекста Provider оборачивается вокруг компонента Child. Обратите внимание на провайдера.

<Provider value={this.state}>
  <Child />
</Provider>

В компоненте Provider установлено значение {this.state}. В компоненте Дочерний есть Потребитель, который подписывается на значение, указанное Поставщиком. В данном случае этим значением является состояние. ПРИМЕЧАНИЕ. Провайдер ВСЕГДА должен оборачивать Потребителя. Это не будет работать, если компоненты с Потребителями не имеют Поставщика.

The Child. Затем мы создадим компонент Child.

import React from "react"
import { Consumer } from "./Context"
import Grandchild from "./GrandChild"
function Child() {
  return (
    <Consumer>
      {context => (
        <div>
          <h1>Child Component</h1>
          {context.people.map(person => {
            return (
              <p key={person.id}>
                Hi, I am {person.name} and I am {person.age}
                years old.
              </p>
            )
          })}
          <GrandChild />
        </div>
      )}
    </Consumer>
  )
}
export default Child

Ладно, довольно много всего происходит. Давайте разберемся. Сначала импортируется объект контекста Consumer. Затем весь компонент оборачивается объектом контекста Consumer.

<Consumer>
  {context => (
    <div>
      <h1>Child Component</h1>
      {context.people.map(person => {
        return (
          <p key={person.id}>
            Hi, I am {person.name} and I am {person.age} years old.
          </p>
        )
      })}
      <GrandChild />
    </div>
  )}
</Consumer>

Внутри Consumer - {context => ( ... )}. Помните value=this.state от Провайдера? Что ж, контекст внутри Consumer напрямую связан со значением. Это потому, что он подписался на него. Давайте подробнее рассмотрим, как Потребитель использует контекст. ПРИМЕЧАНИЕ: «контекст» - это произвольное имя. Это могут быть данные, собака, бла и т. Д.

{
  context.people.map(person => {
    return (
      <p key={person.id}>
        Hi, I am {person.name} and I am {person.age} years old.
      </p>
    )
  })
}

Поскольку context был передан через потребителя, а context подписывается на состояние Parent, у нас есть доступ к людям! Все, что нам нужно сделать, чтобы получить контент, - это выполнить context.people. Здесь происходит то, что дочерний компонент отображает каждый элемент внутри людей. Затем отображается предложение с указанием имени и возраста каждого элемента people.

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

<Provider value={state: this.state}>
  <Child />
</Provider>

Заметили что-нибудь другое? Вместо value={this.state} теперь value={state: this.state}. Вы абсолютно можете это сделать. Фактически, во второй части этой серии мы будем этим заниматься. Если вы хотите передать несколько значений от Поставщика Потребителю (например, состояние И функция), то способ, которым Потребитель вызывает элемент, будет другим.

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

{
  context.state.people.map(person => {    return (
      <p key={person.id}>
        Hi, I am {person.name} and I am {person.age} years old.
      </p>
    )
  })
}

Обратите внимание, теперь, чтобы использовать значение от Provider, мы должны сказать context.state.people. Мне потребовалась целая вечность, чтобы понять это. Но, надеюсь, это поможет!

Хорошо, давайте посмотрим на компонент GrandChild.

import React from "react"
import { Consumer } from "./Context"
function GrandChild() {
  return (
    <Consumer>
      {context => (
        <div>
          <h1>Grandchild Component</h1>
          {context.people.map(person => {
            return (
              <p key={person.id}>
                Hi, I am {person.name} and I am {person.age} years old                                             
              </p> 
            )
          })}
        </div>
      )}
    </Consumer>
  )
}
export default GrandChild

The GrandChild. Хм… Выглядит знакомо. По функциональности он почти такой же, как и компонент Child. Весь компонент по-прежнему заключен в Consumer. Это позволяет передавать состояние от Parent.

<Provider value={this.state}>
  <Child />
</Provider>

Помните это? Это в родительском компоненте. Провайдер обтекает Дочерний. Внутри Child есть GrandChild. Это означает, что GrandChild имеет доступ для подписки на значение, указанное Поставщиком. Вот почему он может получить доступ к состоянию.

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

<Provider value={this.state}>
  <ComponentOne />
  <ComponentTwo />
</Provider>

Затем просто оберните содержимое каждого компонента с помощью Consumer, и все готово.

Хорошо, наконец-то мы можем запустить наше приложение. Вот как это будет выглядеть.

Дочерний компонент - это первый компонент, который получает состояние от поставщика контекста. Затем он предшествует передаче состояния внуку. Как видите, даже компонент Grandchild, заключенный в компонент Child, имеет доступ к состоянию Parent.

Заключение

Итак, мы узнали, как использовать контекстный API React в простом приложении. Состояние от Родителя передается потомкам через Провайдер. Потребители используются в дочерних компонентах для подписки на значение, переданное в Provider. Не так уж и плохо, правда? Ознакомьтесь с частью 2, где я покажу вам, как обновить состояние Родителя с Потребителем.

Ресурсы

Первоначально опубликовано на https://techflip.netlify.com.