React中组件使用context通信的方式

1,659 阅读3分钟

context可以理解为一种全局的上下文变量。通过context我们可以跨级组件通信时不用在每一个组件使用props来传递值,直接在组件树之间来传递值和方法。只要是提供context组件的子组件都可以访问到context上的值。

Props

context

提供context的组件可以理解为生产者(provider),使用context的组件可以理解为消费者(consumer)。生产者通常为一个顶层的父组件,消费者通常为子组件。

1、context

Legacy Context

生产者

生产者(父组件)需要使用childContextTypes来定义提供的context的值,然后再使用getChildContext给定义的context赋值,需要注意的是childContextTypesgetChildContext必须同时一起使用:

import React from 'react'
import PropTypes form 'prop-types'
import Middle from './middle'

class Father extends React.Component {
    // 给定义context赋值
    getChildContext() {
      return {
        name: 'cauth',
        age:18.
        work: () => 'coding'
      }
  }
  render() {
      return (
        <h1>Fathter component</h1>
        <Middle />
      )
  }
}

// 1、定义context提供的值
Father.childContextTypes = {
    name: PropTypes.string,
    age: PropTypes.number,
    work: PropTypes.func
}

Middle代码

import React from 'react'
import Child from './child'

class Middle extends React.Component {
  render() {
    return (
      <Child />
    )
  }
}

export default Middle

消费者

消费者首先需要使用contextTypes声明需要的context,如果没有声明获取到的值时undefined;然后再从context中获取到所需要的值。

import React from 'react'
import PropTypes from 'prop-types'

class Child extends React.Component {
  render() {
    const { name, age, work } = this.context // 获取context的值
    return (
      <div>
        <p>My name is { name } and { age } years old</p>
        <button onClick={() => {alert(work())}}>点击调用父组件传递的方法</button>
      </div>
    )
  }
}

// 定义子组件需要使用的context
Child.contextTypes = {
    name: PropTypes.string,
    age: PropTypes.number,
    work: PropTypes.func
}

export default Child

使用context有以下四个关键的地方

  1. childContextTypes,在生产者中定义提供的context
  2. getChildContext,在生产者中给定义的context赋值
  3. contextTypes,在消费者中定义需要的context(如果不定义会报错)
  4. const { xx, xx } = this.context,从context中获取值

除了从this.context获取context还能从哪里获取呢?🤔

  • constructor(props, context)
  • componentWillReceiveProps(nextProps, nextContext)
  • shouldComponentUpdate(nextProps, nextState, nextContext)
  • componentWillUpdate(nextProps, nextState, nextContext)

但是需要注意的是如果使用LegacyContext在消费者中使用了PureComponent,如果生产者对context进行改变,消费者不会发生新的render

createContext

React.createContext,在为使用context时提供了一种全新API,更加贴切我们的使用习惯。使用createContext会创建一个provider以及consumer,这样的语法更加类似与生产者消费者模式。

生产者

首先在生产者中使用createContext创建一个context,然后使用context上的provider方法给子组件提供相应的context值。

import React from 'react'
import Child from './child'

export const GlobalContext = React.createContext({'name': 'who?', age: 0})

class Father extends React.Component {
    render() {
        return (
            <div>
                // 使用value来定义context提供的值
                <GlobalContext.provider value={{name: 'cauth', age: 18}}>
                    <Child />
                </GlobalContext>
            </div>
        )
    }
}

消费者

消费者首先要获取到全局的context然后调用其consumer方法,需要注意的是consumerchild必须是一个函数

import React from 'react'
import { FatherContext } from './father'

class Child extends React.Component {
  render() {
    return (
      <FatherContext.Consumer>
        {
          context => { // context表示provider中value提供的值
            const {name, age}  = context
            return (
              <div>
                {name}---{age}
              </div>
            )
          }
        }
      </FatherContext.Consumer>
    )
  }
}

export default Child

context缺点

  1. 用于在组件使用了context,代码耦合度较高,不利于组件复用。
  2. context相当于一个全局变量,在使用的不能方便的追踪到数据源。