10. React的上下文Context
1. Context的作用
组件间的参数传递是单向数据流(父->子),那么如果当子组件嵌套的很深层的时候,就会存在每一层嵌套的过程中都需要通过props进行传参,十分麻烦,要是在整个组件树中能有一个公共的“全局变量”那就好了, 每次我们需要相应的参数只要通过访问这个全局变量就可以达到我们想要的目的了,因此我们使用了上下文Context
2. Context三剑客
- React.createContext(): 用于创建一个上下文
- Provider: 用于为组件树提供特定的上下文
- Consumer: 在组件树内获取特定的上下文内容
简单的Context使用方法
import React, { Component } from "react";
// 创建两个不同的上下文
const ComponentTreeParam = React.createContext();
// 这两个不同的上下文通过不同的属性名进行区分
const ComponentTreeParamV2 = React.createContext();
class Inner extends Component {
list(elem) {
console.log(elem);
return elem.map((x, index) => (
<div key={index}>
姓名:{x.name} / 年龄: {x.age}
</div>
));
}
render() {
return (
<div>
// 直接这里的就是provider传入的参数
// 然后返回一个jsx就可以插入dom中
<ComponentTreeParam.Consumer>
{elem => this.list(elem)}
</ComponentTreeParam.Consumer>
<div>恭喜发财</div>
<ComponentTreeParamV2.Consumer>
{elem => this.list(elem)}
</ComponentTreeParamV2.Consumer>
<br />
// 将多个不同的context嵌套在一起使用
<ComponentTreeParam.Consumer>
{theme1 => {
return (
<ComponentTreeParamV2>
{theme2 => {
return [...this.list(theme1), ...this.list(theme2)];
}}
</ComponentTreeParamV2>
);
}}
</ComponentTreeParam.Consumer>
</div>
);
}
}
class ToolBar extends Component {
render() {
return <Inner />;
}
}
class Context extends Component {
render() {
const collections = [
{ name: "Zhangsan", age: 18 },
{ name: "LiSi", age: 20 }
];
const collections2 = [
{ name: "Zhangsan", age: 35 },
{ name: "LiSi", age: 38 }
];
return (
// 将collection作为Provider的值传入该组件树
<ComponentTreeParam.Provider value={collections}>
<div>
// 将collection2作为Provider的值传入该组件树
<ComponentTreeParamV2.Provider value={collections2}>
<ToolBar />
</ComponentTreeParamV2.Provider>
</div>
</ComponentTreeParam.Provider>
);
}
}
export default Context;
动态Context的绑定
import React, { Component } from "react";
const style = {
light: {
background: "yellowgreen",
color: "#ffdfd1"
},
dark: {
background: "black",
color: "white"
}
};
const ThemeContext = React.createContext();
class Box extends Component {
loadStyle(theme) {
console.log(theme);
return (
<div>
<div style={theme.color}>我会变色</div>
<button onClick={theme.changeMethod}>我也可以帮你变色</button>
</div>
);
}
render() {
return (
<div>
<ThemeContext.Consumer>
// theme中包含了color和改变theme的方法
// 调用相应的方法就可以改变主题了
{(theme) => this.loadStyle(theme)}
</ThemeContext.Consumer>
</div>
);
}
}
class ToolBar extends Component {
// 在中间组件中不用传递参数
render() {
return <Box />;
}
}
class DynamicContext extends Component {
constructor(props) {
super(props);
this.state = {
colorTheme: style.light
};
}
changeTheme() {
console.log(this.state.colorTheme);
this.setState(state => ({
colorTheme: state.colorTheme === style.light ? style.dark : style.light
}));
}
render() {
const _this = this;
// 通过绑定state到provider的value上,然后通过js动态变化state
// 可以在根组件中定义使状态绑定的函数,这个方法就会在整个组件树中得到绑定
return (
<div>
<ThemeContext.Provider
value={{
color: _this.state.colorTheme,
changeMethod: _this.changeTheme.bind(_this)
}}
>
<ToolBar />
</ThemeContext.Provider>
<button onClick={this.changeTheme.bind(this)}>变色吧</button>
</div>
);
}
}
export default DynamicContext;
**Notes: **:
- Context主要用于一个组件树内的状态共享
- 先通过React.createContext()创建一个组件树的上下文,之后通过new一个上下文的实例, 然后通过Provider将该状态注入到子组件中,在子组件外部添加Consumer获得相应的上下文对象
- 调用注入value的方法,可以通过(param) => {}这个箭头函数注入,其中param就是我们注入的value值
- 可以嵌套注入,在最内部组件可以获得外部注入内容的所有参数
- 动态Context主要是可以将改变父组件状态的方法以参数的形式传入,这样可以在深层的组件中修改上级,上上级…的状态