参考链接:【https://medium.com/search?q=ReactContext】
在嵌套组件中我们常常遇到这样一个问题:在这个组件的局部作用域当中可以在任意层组件中读取这个变量,之前的做法是一步一步传递props,但是这样的作法太过于繁琐,使用Redux 库 eventHub模式也能完成,但是多次调用函数也很麻烦(当然了eventHub也有其他的功能),React框架提供了Context API 可以很好地实现通过组件树提供一个传递数据的方法,从而避免了在每一个层级手动的传递 props 属性 。
1. Context API 的组成
有三个组成函数
- Consumer —— 订阅Context的值得变化
- Provider —— 当 React 渲染 context 组件 Consumer 时,它将从组件树的上层中最接近的匹配的 Provider 读取当前的 context 值(作用就是让Context值强行暴露给Consumer)
2. 使用方法:在这里举实现一个主题变换的例子
1. 第一步 React.createContext
声明一个Context
const themeContext = React.createContext();
2. 第二步 Provider
React组件默认允许Provider 订阅Context的变化,接收一个 value 属性传递给 Provider 的后代 Consumers。一个 Provider 可以联系到多个 Consumers。Providers 可以被嵌套以覆盖组件树内更深层次的值。
<Provider value={/* some value */}>
<div>
<div>{/*可以有多层组件*/}<div>
</div>
<Provider>
【注意】Consumer的值不能挂在组件树当中,必须写在Constructor中,所以Consumer的值变化只能读取,不能修改,若非要修改必须在顶层class组件中声明一个函数来修改。
//举例
class App extends React.Component {
change = ()=>{
if(this.state.theme === 'green'){
this.setState({theme:'red'})
}else{
this.setState({theme:'green'})
}
}
constructor() {
super();
this.state = {
theme: "green"
};
}
render() {
return (
<themeContext.Provider value={this.state.theme}>
<div className="App">
<button onClick={this.change}>换肤</button>
<div>
<Box theme={theme}>
<Button />
</Box>
<Box theme={theme}>
<Input />
</Box>
</div>
</div>
</themeContext.Provider>
);
}
}
3. 第三步 Consumer
接收一个 函数作为子节点. 函数接收当前 context 的值并返回一个 React 节点。传递给函数的 value
将等于组件树中上层 context 的最近的 Provider 的 value
属性。如果 context 没有 Provider ,那么 value
参数将等于被传递给 createContext()
的 defaultValue
使用Consumer 订阅Context 值的举例:
//第二步的方法应该写成这样
class App extends React.Component {
change = ()=>{
if(this.state.theme === 'green'){
this.setState({theme:'red'})
}else{
this.setState({theme:'green'})
}
}
constructor() {
super();
this.state = {
theme: "green"
};
}
render() {
return (
<themeContext.Provider value={this.state.theme}>
<div className="App">
<button onClick={this.change}>换肤</button>
<themeContext.Consumer>
{theme => (
<div>
<Box theme={theme}>
<Button />
</Box>
<Box theme={theme}>
<Input />
</Box>
</div>
)}
</themeContext.Consumer>
</div>
</themeContext.Provider>
);
}
}