React 的 Context API

写在前面

上下文(Context) 提供了在组件之间共享这些值的方法,而不必在树的每个层级显式传递一个 prop 。

普通传递

import React, { Component } from 'react'

class Grandpa extends Component {
  state = {
    info: 'GrandPa组件的信息',
  }
  render() {
    return (
      <div>
        <Father info={this.state.info} />
      </div>
    )
  }
}

class Father extends Component {
  render() {
    return (
      <div>
        <Son info={this.props.info} />
      </div>
    )
  }
}

class Son extends Component {
  render() {
    return <div>我是Son组件,拿到信息为:{this.props.info}</div>
  }
}

export default Grandpa

页面输出:

我是Son组件,拿到信息为:GrandPa组件的信息

我们会发现这样的缺点是一层一层传值,如果有更多层级和更多数据的话,会让代码看起来很不整洁,如果中间哪个组件忘了传值基本就完了

如果使用 context,就能帮我们解决这个层级不停传值的问题。

旧版 Context API

将上面的代码稍作修改

import React, { Component } from 'react'
import PropTypes from 'prop-types'

class Grandpa extends Component {
  state = {
    info: 'GrandPa组件的信息',
  }
  getChildContext() {
    return { info: this.state.info }
  }
  render() {
    return (
      <div>
        <Father />
      </div>
    )
  }
}
// 声明Context对象属性
Grandpa.childContextTypes = {
  info: PropTypes.string,
}

class Father extends Component {
  render() {
    return (
      <div>
        <Son />
      </div>
    )
  }
}

class Son extends Component {
  render() {
    return <div>我是Son组件,拿到信息为:{this.context.info}</div>
  }
}
// 根据约定好的参数类型声明
Son.contextTypes = {
  info: PropTypes.string,
}
export default Grandpa

在需要传出去的 context 值和需要接收 context 值都要进行类型检查判断。

三个组件的层级关系如下

<GrandPa>
  <Father>
    <Son />
  </Father>
</GrandPa>

正常用这个 api 可能没什么问题,但如果中间哪个组件用到shouldComponentUpdate方法的话,就很可能出现问题。
如果在 GrandPa 组件设置按钮点击可以更新 info 的值,即通过this.setState({info: ‘改变值’})方法 更新 Context: 那么

  • GrandPa 组件通过 setState 设置新的 Context 值同时触发子组件重新 render。
  • Father 组件重新 render。
  • Son 组件重新 render,并拿到更新后的 Context。

假如在 Father 组件添加函数

shouldComponentUpdate () {
    return false
}

这会导致 Son 组件也不会重新 render,即无法获取到最新的 Context 值。
这样的不确定性对于目标组件来说是完全不可控的,也就是说目标组件无法保证自己每一次都可以接收到更新后的 Context 值。

新版 Context API

新版 Context 新增了 creactContext() 方法用来创建一个 context 对象。这个对象包含两个组件,一个是 Provider(生产者),另一个是 Consumer(消费者)。

  1. Provider 和 Consumer 必须来自同一个 Context 对象,即一个由 React.createContext()创建的
    Context 对象。
  2. React.createContext()方法接收一个参数做默认值,当 Consumer 外层没有对应的 Provider
    时就会使用该默认值。
  3. Provider 组件使用 Object.is 方法判断 prop 值是否发生改变,当 prop 的值改变时,其内部组件树中对应的
    Consumer 组件会接收到新值并重新渲染。此过程不受 shouldComponentUpdete 方法的影响。
  4. Consumer 组件接收一个函数作为 children prop 并利用该函数的返回值生成组件树的模式被称为 Render Props 模式
// 创建一个 context 对象, 该对象包含 Provider 和 Consumer 两个属性,
const InfoContext = React.createContext('')
// 使用 Provider 组件生成一个 context
class Grandpa extends Component {
  state = {
    info: 'GrandPa组件的信息',
  }
  render() {
    return (
      <InfoContext.Provider value={{ info: this.state.info }}>
        <Father />
      </InfoContext.Provider>
    )
  }
}
// 使用 Consumer 组件获取 context 对象的值
class Son extends Component {
  render() {
    return (
      <InfoContext.Consumer>
        {value => {
          return <div>我是Son组件,拿到信息为:{value.info}</div>
        }}
      </InfoContext.Consumer>
    )
  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值