定义
在一个典型的 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。