context 被译为上下文,在 react 中当你不想通过 props 或 state 逐层传递数据时,就可以使用 context 实现跨层级的组件数据传递。
如果使用 context ,需要两种组件,一个是 生产者 Provider ,通常是一个父组件;另一个是 context 的消费者,通常是一个或多个子组件,也就是说 context 是基于生产者消费者模式的。
对于父组件,需要通过一个静态属性 childContextTypes 声明提供给子组件的 context 对象属性,并实现一个实例 getChildContext 方法,返回一个代表 context 的纯对象。
import React from 'react'
import PropTypes from 'prop-types'
class MiddleComponent extends React.component {
render (){
return <ChildComponent />
}
}
class ParentComponent extends React.Component {
// 声明 context 对象属性
static childContextTypes = {
propA: propTypes.string,
methods: propTypes.func
}
// 返回 context 对象函数,方法名是约定好的
getChildContext(){
return{
propA: 'propA',
methodA: () => 'methodA'
}
}
render(){
return <MiddleComponent />
}
}
子组件通过以下方式访问父组件提供的 context:
import React from 'react';
import propTypes from 'prop-types';
class childComponent extends React.Component{
// 声明需要使用的 context 属性
static contextTypes = {
propA: propTypes.string
}
render(){
const { propA, methodA } = this.context;
console.log(`context.propA = ${propA}`); // context.propA = propA;
console.log(`context.methodA = ${methodA}`); // context.methodA = methodA;
return ...
}
}
子组件需要通过声明一个静态 contextTypes 后,才能访问父组件 context 对象的属性,否则即使属性名写的正确,拿到的对象也是 undefined。
而对于无状态子组件,可以通过如下方式访问父组件的 context:
import React from 'react';
import propTypes from 'prop-types';
const ChildComponent = (props, context) => {
const { propA } = context;
console.log(`context.propA = ${propA}`); // context.propA = propA;
return ...
}
ChildComponent.contextProps = {
propA: propTypes.string
}
在新版本中,更明确了生产者消费者模式的使用:
import React from 'react';
import ReactDom from 'react-dom';
const ThemeContext = React.createContext({
background: 'red',
color: 'green'
});
class App extends React.Component{
render(){
return(
<ThemeContext.Provider value={background:'red',color:'green'}> // value 相当于 getChildContext()
<Header />
</ThemeContext.Provider>
)
}
}
通过 createContext 方法创建一个 Context 对象,包含两个组件:<Provider /> 和 <Consumer />,<Consumer /> 的 children 必须是一个函数,通过函数的参数获取<Provider /> 提供的 context:
<ThemeContext.Consumer>
{context => (
<h1 style={{background:context.background,color:context.color}}>
{this.props.children}
</h1>
)}
</ThemeContext.Consumer>
可以直接获取 context 的地方
- 构造方法中:constructor(props,context);
- 生命周期中:componentWillReceiveProps(nextProps,nextContext); shouldComponentUpdate(nextProps,nextContext); componentWillUpdate(nextProps,nextContext);
对于面向函数的无状态组件,可以通过函数的参数直接访问组件的 Context:
const StatelessComponent = (props,context) =>{
...
}
缺点:react App 组件是树状结构,一层一层延伸,父子组件是一对多的线性依赖结构,随意的使用 context 会破坏这种线性依赖关系,导致产生组件之间一些不必要的额外依赖关系,降低组件的可复用性,破坏 App 的可维护性