Использование React Hooks серии 3 в контексте

React.js
Использование React Hooks серии 3 в контексте

Эта статья участвовала в приказе о созыве Haowen, нажмите, чтобы просмотреть:Двойные заявки на внутреннюю и внешнюю стороны, призовой фонд в 20 000 юаней ждет вас, чтобы бросить вызов!

В этой серии будет описано, как использовать React Hooks, начиная с useState, и будет рассмотрено следующее:

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

Сегодня мы поговорим об использовании объекта Context и useContext.

Что такое контекстные API

Рассмотрим такой сценарий, если древовидная структура компонентов следующая, и теперь вы хотите передать атрибут userName из корневого узла в листовой узел ADF, и передать его через props, он неизбежно пройдет через BCE, даже если эти компоненты не используйте этот атрибут userName.

Если такая вложенная древовидная структура имеет 5 или 10 уровней, это будет катастрофический опыт разработки и обслуживания. Этой проблемы можно избежать, если вы можете перейти сразу в нужное вам место, не проходя через промежуточные узлы, тогда Context api здесь для решения этой проблемы.

Контекстный API — это API, который передает данные в дереве компонентов, не проходя через каждый уровень. Давайте посмотрим на использование Context Hook.

использовать контекст

Давайте возьмем пример, чтобы сосредоточиться на самой правой ветви, C E F, передавая переменное имя пользователя из корневого узла в узел F.

Сначала мы создаем App, ComponentC, ComponentE, ComponentF следующим образом.

App.tsx

import React from 'react'

import './App.css'

import ComponentC from './components/16ComponentC'

const App = () => {
  return (
    <div className="App">
      <ComponentC />
    </div>
  )
}

export default App

ComponentC.tsx

import React from 'react'

import ComponentE from './16ComponentE'

function ComponentC() {
  return (
    <div>
      <ComponentE />
    </div>
  )
}

export default ComponentC

ComponentE.tsx

import React from 'react'

import ComponentF from './16ComponentF'

function ComponentE() {
  return (
    <div>
      <ComponentF />
    </div>
  )
}

export default ComponentE

ComponentF.tsx

import React from 'react'

function ComponentF() {
  return (
    <div>
      ComponentF
    </div>
  )
}

export default ComponentF

Страница выглядит следующим образом:

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

создать контекст

Использовать в корневом узле App.tsxcreateContext()создать контекст

const UserContext = React.createContext('')

Создайте объект контекста. Когда React отображает компонент, который подписывается на этот объект Context, компонент будет считывать текущее значение контекста из соответствующего Provider, ближайшего к нему в дереве компонентов.

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

Провайдер

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

<UserContext.Provider value={'chuanshi'}>
  <ComponentC />
</UserContext.Provider>

Каждый объект Context возвращает компонент Provider React, который позволяет потребляющим компонентам подписываться на изменения контекста.

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

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

Изменения определяются путем проверки старых и новых значений по тому же алгоритму, что и Object.is.

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

export const UserContext = React.createContext('')

На данный момент полный код App.tsx

import React from 'react'

import './App.css'

import ComponentC from './components/16ComponentC'

export const UserContext = React.createContext('')

const App = () => {
  return (
    <div className="App">
      <UserContext.Provider value={'chuanshi'}>
        <ComponentC />
      </UserContext.Provider>
    </div>
  )
}

export default App

Потребляйте контекст в используемом узле

импортировать объект контекста

import { UserContext } from '../App'

Потребляйте вместе с потребителем

<UserContext.Consumer>
  {
    (user) => (
      <div>
        User context value {user}
      </div>
    )
  }
</UserContext.Consumer>

Здесь компоненты React также могут подписываться на изменения контекста. Это позволяет вам подписываться на контексты в функциональных компонентах.

Это требует практики функции как ребенок. Эта функция принимает текущее значение контекста и возвращает NoDe odd. Значение, передаваемое на функцию, эквивалентно значению, предоставляемую поставщику, ближайшим к контексту вверх по дерево компонента. Если нет соответствующего провайдера, параметр значения эквивалентен по умолчанию значение для CreateContext ().

Полный код ComponentF.tsx выглядит следующим образом.

import React from 'react'

import { UserContext } from '../App'

function ComponentF() {
  return (
    <div>
      <UserContext.Consumer>
        {
          (user) => (
            <div>
              User context value {user}
            </div>
          )
        }
      </UserContext.Consumer>
    </div>
  )
}

export default ComponentF

Эффект следующий

В настоящее время ситуация хороша, когда есть только один Контекст.Давайте посмотрим на ситуацию с несколькими Контекстами.

Несколько контекстных ситуаций

Добавляем еще один Context в App.tsx

import React from 'react'

import './App.css'

import ComponentC from './components/16ComponentC'

export const UserContext = React.createContext('')
export const ChannelContext = React.createContext('')

const App = () => {
  return (
    <div className="App">
      <UserContext.Provider value={'chuanshi'}>
        <ChannelContext.Provider value={'code volution'}>
          <ComponentC />
        </ChannelContext.Provider>
      </UserContext.Provider>
    </div>
  )
}

export default App

Затем потребляйте их в компоненте F

import React from 'react'

import { UserContext, ChannelContext } from '../App'

function ComponentF() {
  return (
    <div>
      <UserContext.Consumer>
        {
          (user) => (
            <ChannelContext.Consumer>
              {
                (channel) => (
                  <div>
                    User context value {user}, channel value {channel}
                  </div>
                )
              }
            </ChannelContext.Consumer>

          )
        }
      </UserContext.Consumer>
    </div>
  )
}

export default ComponentF

Страница отображается следующим образом

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

useContext

Например, мы передаем компонент E в приведенной выше демонстрации.useContextИспользуйте контекст, созданный корневым узлом. в следующие шаги

  1. импорт из реагирующего объектаuseContextэтот хук API
  2. импортировать объект Context, созданный корневым узлом (можно импортировать несколько)
  3. воплощать в жизньuseContext()метод, проходящий в контексте

Полный код ComponentE:

import React, { useContext } from 'react'

import ComponentF from './16ComponentF'
import {UserContext, ChannelContext} from '../App'

function ComponentE() {
  const user = useContext(UserContext)
  const channel = useContext(ChannelContext)
  return (
    <div>
      <ComponentF />
      --- <br/>
      {user} - {channel}
    </div>
  )
}

export default ComponentE

Страница отображается следующим образом

Ключевая строка кода выглядит следующим образом

const value = useContext(MyContext)

Метод useContext принимает объект контекста (React.createContextвозвращаемое значение) и возвращает текущее значение этого контекста. Текущее значение контекста определяется ближайшим компонентом верхнего компонента к текущему компоненту.<MyContext.Provider>изvalueопорное решение.

Когда самый верхний компонент компонента является ближайшим<MyContext.Provider>При обновлении этот хук вызывает повторный рендеринг с последним переданнымMyContextконтекст провайдераvalueстоимость. даже если предки используютReact.memoилиshouldComponentUpdate, также используется в самом компонентеuseContextповторно рендерить.

можно понимать как,useContext(MyContext)Эквивалент компонента класса вstatic contextType = MyContextили<MyContext.Consumer>.

useContext(MyContext)Просто позволяет читать значение контекста и подписываться на изменения в контексте. Вам все еще нужно использовать в верхнем дереве компонентов<MyContext.Provider>для обеспечения контекста для базовых компонентов.

На данный момент мы освоили использование API-интерфейса useContext и видим, что использование useContext может значительно снизить сложность кода, используемого несколькими контекстами.

В следующей главе мы поговорим об использовании useReducer.