使用 react Context API 的正确姿式

本文介绍一下 React 中常见的 Context API 的使用方式。在使用 Context API 以前,咱们还须要知道为啥要使用。❓react

为啥要用 Context API

考虑到组件有可能 层层嵌套 ,在传 props 的过程当中,若是书写大量的 ...propspropName={this.props.propValue} 会致使代码灰常丑陋 🤢:api

20190312085239.png

一层一层下来就像这样:ide

<App>
    <Switcher toggleState={this.state.toggle}>
        <Pannel toggleState={props.toggleState}>
            <div onClick={handleClick}>{props.toggleState ? '✔' : '❌'}

因此引入 Context API 就能够直接经过上下文跨层级获取数据:函数

如何使用

  • 而后建立 provider 👇
  • 首先要引入 React 内置的 React Context API 📦
  • 最后建立 consumer 👆

建立 Provider

增长一个名为 ToggleContext.js 的文件做为上下文📜,里头定义一系列须要跨层级使用的 state 和 functionthis

import React, { createContext } from 'react'

// 1. 使用 createContext 建立上下文
const ToggleContext = createContext({
    toggle: true,
    handleToggle: () => {}
})

// 2. 建立 Provider
export class ToggleProvider extends React.Component {

    // 注意书写顺序;handleToggle 做为箭头函数不能 bind 所以须要写在上面;若是不喜欢这样的顺序则能够书写普通函数放在下面但记得 bind
    handleToggle = () => {
        this.setState({ toggle: !this.state.toggle })
    }

    // 2-1. 重写 state 
    state = {
        toggle: true,
        handleToggle: this.handleToggle
    }

    render() {
        // 2-2. 经过 Provider 组件的 value 将 state 提供出去
        return (
            <ToggleContext.Provider value={this.state}>
                {this.props.children}
            </ToggleContext.Provider>
        ) 
    }
}

// 3. 建立 Consumer
export const ToggleConsumer = ToggleContext.Consumer

上面的代码主要分为三大部分:spa

// 建立 Context
const ToggleContext = createContext()

// 建立 Provider
export class ToggleProvider extends React.Component {}

// 建立 Consumer
export cnost ToggleConsumer = ToggleContext.Consumer

咱们理一下步骤🏃‍code

  • 首先,咱们须要引入 createContext 上下文并调用,传入咱们但愿在其余层级组件中使用的 state 和改变 state 的方法,注意这里的 state 和方法只是一个“骨架”,后面的 Provider 会覆盖
  • 接下来建立 Provider 这里头维护真正的 state,并经过 render 函数里面的 Context.Provider 组件的 value 属性提供这些方法
  • 而后建立 Consumer,直接导出 Context.Consumer 给外部使用便可

使用 Provider

ToggleProvider 组件包装了一系列共享的状态,为了使用这些组件的状态,咱们直接将其添加到 App 组件中:blog

import React from 'react';
import { ToggleProvider } from './ToggleContext' // 1. 获取 Provider

function App() {
  // 2-1. 使用 ToggleProvider 组件
  // 2-2. 若是有其余组件同样能够共享 state
  return (
    <ToggleProvider>
      <Switcher></Switcher>
      {/* 其余组件仍然能够经过 props 访问到共享的 state */}
    </ToggleProvider>
  );
}

// ...
export default App;

使用 Provider 比较简单直接做为父组件包裹在上层便可。若是组件内部有其余多个组件,这些组件均可以共享 Provider 提供的 staterem

使用 Consumer

  • 经过 Consumer 直接使用 props 传递的 state 属性在 render 函数中渲染便可
  • 若是须要调用方法,则可调用 props 传递的函数
import React from 'react';
import { ToggleProvider, ToggleConsumer } from './ToggleContext' // 1. 获取 Provider 和 Consumer

function App() {
  return (
    <ToggleProvider>
      <Switcher></Switcher>
    </ToggleProvider>
  );
}

const Switcher = () => {
  return <Pannel />
}

const Pannel = () => {
  // 在多个层级内直接经过 props 获取 state 和方法,调用方法改变 state
  return (
    <ToggleConsumer>
      {({ toggle, handleToggle }) => <div onClick={() => handleToggle()}>{ toggle ? '✔' : '❌'}</div>}
    </ToggleConsumer>
  )
}

export default App;

直接在子组件内部经过 props 调用便可get

小结

另外附上一个简易版的 Context:

  • 经过 createContext 建立一个名为 color 的 context
  • 经过 Provider 的 value 属性传值
  • 经过 Consumer 的 props 接收值
import React, { createContext } from "react";

const { Provider, Consumer } = createContext("color"); // 建立 Context 引用 Provider 和 Consumer

class DeliverComponent extends React.Component {
  // 维护一个 state
  state = {
    color: 'orange',
    handleClick: () => {
      this.setState({ color: 'red' })
    }
  }
  render() {
    return (
      <Provider value={this.state}>
        <MidComponent />
      </Provider>
    )
  }
}

const MidComponent = () => <Receiver />; // 中间包含多层级的组件

const Receiver = () => ( // 须要使用的后代元素使用 Consumer
  <Consumer>
    {({ color, handleClick }) => <div style={{ color }} onClick={() => { handleClick() }}> Hello, this is receiver.</div>}
  </Consumer>
);

const App = () => <DeliverComponent />;

export default App;

参考: