当我们需要使用到一个数据,需要传递多层的时候,props往往显得心累,而我们又不需要引入redux的时候,可以使用react的context
首先使用createContext创建一个一个context,它会有两个方法Provider和Consumer,功能如同字义,一个是提供者,就是数据的发起者,一个是消费者,就是数据的接受者
createContext生成的Provider对应Cosumer是一对,所以需要创建一个JS文件,将生成的两者导出,我们才能更好的在不同文件下使用
import { Component, createContext } from "react";
const { Consumer: MyConsumer, Provider: MyProvider } = createContext()
export { MyConsumer, MyProvider }
创建一个 最外层文件App.js -> 父级文件Wrap.js -> 子级文件Inner.js
App.js
ReactDOM.render(<MyProvider value={{a: 1}}><Wrap/></MyProvider>, document.getElementById("root"))
Wrap.js
import { Component } from "react";
import Inner from './Inner'
class Wrap extends Component {
render() {
return <Inner></Inner>
}
}
export default Wrap
import { Component } from "react";
import {MyConsumer} from './Provider'
class Inner extends Component {
render() {
return <MyConsumer>
{(context) => { console.log(context); }}
</MyConsumer>
}
}
export default Inner
就可以看见在Inner组件中得到并输出了由最外层的context数据,而不是通过像props需要一层一层的传递下来的
我们也可以对Provider和Consumer进行封装导出
import { Component, createContext } from "react";
const { Consumer: MyConsumer, Provider } = createContext()
class MyProvider extends Component {
render() {
// ...
return <Provider value={{...this.props.value}}>
...
{this.props.children}
...
</Provider>
}
}
export { MyConsumer, MyProvider }
过时的API(16.3版本前)
废弃原因:当消费者组件A改变context内容时,如果中间组件B不依赖context,那么shouldComponentUpdate就不会发觉变化,如果返回了false,就不会rerender,最终导致后面的依赖context的子组件也不会rerender,这不是我们想要的结果。而新版API会有穿透的能力
使用方式:组件添加 childContextTypes
和 getChildContext,那么它下面的所有组件都能通过
contextTypes获取到context
class MessageList extends React.Component {
getChildContext() {
return {color: "red"};
}
render() {
return <Message />;
}
}
MessageList.childContextTypes = {
color: PropTypes.string
};
class Message extends React.Component {
// B如果不依赖context,就可能影响下面子组件的rerender
// shouldComponentUpdate(nextProps, prevState) {
// if (...) {
// return false;
// }
// return true;
// }
render() {
return <Button>点击</Button>
}
}
class Button extends React.Component {
render() {
return (
// 通过this.context访问
<button style={{background: this.context.color}}>
{this.props.children}
</button>
);
}
}
// 子孙组件可通过contextTypes就能获取到context
Button.contextTypes = {
color: PropTypes.string
};