React中的Context

 

定义

在一个典型的 React 应用中,数据是通过 props 属性自上而下(由父及子)进行传递的,但这种做法对于某些类型的属性而言是极其繁琐的(例如:地区偏好,UI 主题),这些属性是应用程序中许多组件都需要的。Context 提供了一种在组件之间共享此类值的方式,而不必显式地通过组件树的逐层传递 props。

简单地说context的作用就是在某个父组件中定义一个全局状态,这个状态可以在该父组件下的所有子组件中跨级传递共享

在官方文档中,并不推荐我们使用这个API,因为这会使得组件的复用性变差。

虽然说不要用,但是我们也是要了解下这个API到底是干嘛的,毕竟有些优秀的库都是通过这个API实现而来,如:React-Redux。

目前context有两个版本,分别是16.x之前和16.x之后的版本。

 

老版本的Context

在老版本中有如下几个方法:

 

getChildContext: 在父组件中声明一个函数,返回的结果是一个对象,这个对象就是context,可以对子组件进行共享的状态。

 

childContextTypes: 在父组件中声明,执行context中的数据类型,如果不指定会产生错误。

 

contextTypes: 在子孙组件中进行声明,指定要接受context中哪些数据类型。

 

react15.5已经弃用React.PropTypes,需要安装prop-types库。

父组件DetailView.js

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import Welcome from '../components/Welcome';

class DetailView extends Component {
  constructor(props) {
    super(props);
    this.state = {
      propA: 'propA',
    };
  }

  static childContextTypes = {
    propA: PropTypes.string,
    methodA: PropTypes.func,
  }
  
  // 返回Context对象,方法名是约定好的
  getChildContext () {
    const { propA } = this.state;
    return {
      propA: propA,
    };
  }
  
  changeContext = () => {
    this.setState({propA: 'propB'})
  }

  render() {
    return (
      <div className={styles.containor}>
        <button onClick={this.changeContext}>修改context</button>
        <Welcome />
      </div>
    );
  }
}

export default DetailVi

子组件Welcome.js

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

class Welcome extends Component {
  static contextTypes = {
    propA: PropTypes.string
  }
  render() {
    console.log(this.context);
    return (
      <div>
        welcome
      </div>
    );
  }
}

export default Welcome

 

如果contextTypes定义在某个组件中,则这个组件的生命周期函数中会增加一个参数:

constructor(props, context)
componentWillReceiveProps(nextProps, nextContext)
shouldComponentUpdate(nextProps, nextState, nextContext)
componentWillUpdate(nextProps, nextState, nextContext)
componentDidUpdate(prevProps, prevState, prevContext)

 

如果在无状态组件中使用context则如下:

const PropTypes = require('prop-types');

const Button = ({children}, context) =>
  <button style={{background: context.color}}>
    {children}
  </button>;

Button.contextTypes = {color: PropTypes.string}

 

新版本的Context

新版本中使用Provider和Consumer模式,在顶层Provider中传入value,在子孙中的Consumer中获取该值,并且能够传递函数,用来修改context。

 

父组件DetailView.js

import React, { Component } from 'react';
import Goodbye from '../components/Goodbye';

export const { Provider, Consumer } = React.createContext('默认名称');

class DetailView extends Component {
  constructor(props) {
    super(props);
    this.state = {
      propA: 'propA',
      name: '张三',
    };
  }
  
  changeContext = () => {
    this.setState({
      name: '李四',
    });
  }

  render() {
    const { name } = this.state;
    return (
      <div className={styles.containor}>
        <button onClick={this.changeContext}>修改context</button>
        <Provider value={name}>
          <Goodbye />
        </Provider>
      </div>
    );
  }
}

export default DetailVi

子组件Goodbye .js

import React, { Component } from 'react';
import { Consumer } from '../Detail/DetailView';//引入父组件的Consumer容器

class Goodbye extends Component {
  render() {
    return (
      <div>
        goodbye
        <Consumer>
          {
            (name) => <span>{name}</span>
          }
        </Consumer>
      </div>
    );
  }
}

export default Goodbye

Consumer的children必须是一个函数。

这个函数接受当前的context值,返回一个react节点。传递给函数的value值等同于往上组件树离这个context最近的Provider提供的value值。如果没有对应的Provider,value参数等于传递给createContext()的defaultValue。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值