React的context的使用

282 阅读3分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第27天,点击查看活动详情

使用说明

我们使用context时的步骤为三步:

  1. 使用React.createContext()创建context对象
  2. 使用provider 传递value
  3. 子组件消费,有三种途径:contextType(类组件)、useConetxt(函数组件方法)、<Context.Consumer>标签(类组件函数组件通用)

【注意】使用多个context实例时需注意,Class.contextType只能订阅单一context,多个会被覆盖。

step1. 创建context对象

Context说明: 创建一个 Context 对象。当 React 渲染一个订阅了这个 Context 对象的组件,这个组件会从组件树中离自身最近的那个匹配的 Provider 中读取到当前的 context 值。

创建Context对象: 创建context.js文件:

import React from 'react';
export const Context = React.createContext()
export const UserContext = React.createContext()

【注意】Context实例必须在单独文件中声明,不能声明在父组件文件中然后export,否则会在contextType(类组件)消费时报错Uncaught ReferenceError: Cannot access 'UserListContext' before initialization

step2. 使用provider 传递value

Provider说明:

Provider 接收一个 value 属性,传递给消费组件,允许消费组件订阅 context 的变化。一个 Provider 可以和多个消费组件有对应关系。多个 Provider 也可以嵌套使用,里层的会覆盖外层的数据。

当 Provider 的 value 值发生变化时,它内部的所有消费组件都会重新渲染。Provider 及其内部 consumer 组件都不受制于 shouldComponentUpdate 函数,因此当 consumer 组件在其祖先组件退出更新的情况下也能更新。

Provider使用: 创建index.js

import React, { Component } from 'react';
import { Context, UserContext } from './context';
import Child from './child';

// 使用单一Context
// class MyContext extends Component {
//   render() {
//     return (
//       <Context.Provider value={'red'}>
//         父组件
//         <br />
//         <Child />
//       </Context.Provider>
//     )
//   }
// }

// 使用两个context
function MyContext() {
  return(
    <Context.Provider value={'red'}>
      父组件2
      <UserContext.Provider value={'小明'}>
        使用两个context
        <Child />
      </UserContext.Provider>
    </Context.Provider>
  )
}
export default MyContext;

step3. 子组件消费:三种方式

1. 使用contextType(类组件)

import React, { Component } from 'react';
// 需要使用同一个context
import { Context, UserContext } from './context';
class Child extends Component {
  // 使用contextType消费,传入的值会自动挂在this.context中
  static contextType = Context
  // 无法使用contextType分别消费两个Context实例,this.context的值会被覆盖
  // static contextType = UserContext
  render() {
    console.log(this.context)
    return (
     <div style={{color: this.context}}>
      使用contextType消费:取到的context值 {this.context}
    </div>)
  }
}
export default Child;

Class.contextType只能订阅单一context,多个会被覆盖。

2. 使用useConetxt(函数组件方法)

import React, { useContext } from 'react';
import { Context, UserContext } from './context';

function Child() {
  const val = useContext(Context)
  // 可以使用useContext分别来消费两个context实例
  const name = useContext(UserContext)
  return(
  <div style={{color: val}}>
    使用useContext消费:取到的context值 {val}<br/>
    {/* 第二个context值 {name} */}
  </div>)
}
export default Child;

3. 使用<Context.Consumer>标签(类组件函数组件通用)

使用语法:<Context.Consumer>标签中间接收一个回调函数,回调函数的参数就是这个context实例传递的值,然后其回调函数return的jsx中就可以使用传进来的值了。

<Context.Consumer>{ (value)=> <div> {value} </div> }</Context.Consumer>
import React, { Component, useContext } from 'react';
import { Context, UserContext } from './context';

class Child extends Component {
  render() {
    return(
      <div>
        <Context.Consumer>
          { (color)=> <div style={{color}}>Context.Consumer-class组件取值:{ color }</div> }
        </Context.Consumer>
        {/* <UserContext.Consumer>
          { (name)=> <div>第二个context值:{ name }</div> }
        </UserContext.Consumer> */}
    </div>)
  }
}

// 函数组件使用Context.Consumer
// function Child() {
//   return(<>
//     <Context.Consumer>
//       { (color)=> <div style={{color}}>Context.Consumer-函数组件取值:{ color }</div> }
//     </Context.Consumer>
//     {/* <UserContext.Consumer>
//     { (name)=> <div>第二个context值:{ name }</div> }
//     </UserContext.Consumer> */}
//   </>)
// }

export default Child;

使用context总结及注意事项

  1. 使用React.createContext()创建context,并在父组件中使用<Context.Provider value={xx}>传值。【注】最好将声明对象的步骤放在单独文件中,否则在class组件消费时会报错。
  2. 消费的三种方法:
  • contextType方法只受限于类组件,且不能使用多层的context嵌套传值,只可订阅单一context对象;
  • useConetxt方法需要使用在函数组件或自定义hook,可以接收多层context的传值
  • <Context.Consumer>这种方法类组件和函数组件都可以通用,且不限制是否多层context传值,比较灵活,但其特点是写法比较麻烦,需要接收回调函数。