文章概览
本文包含新版本react contextAPI的简单介绍、基本用法和实际项目中的使用方法。
本文不会介绍context和高阶组件的概念,而是介绍二者如何配合使用。
简介
react在16.3版本引入了全新的context api,提供一种跨组件传递数据的方法,避免了在多组件层级间手动传递props。
基本用法
项目中很多组件需要共有的状态比如:主题、地区偏好。如何优雅的处理呢?当然了,借助redux、mobx这些状态库可以轻松实现。但是小项目中无需引入redux等增加复杂度,让新手迷惑。
我们考虑使用context如何处理上边的问题,下边的例子为按钮添加light或dark主题:
- 创建主题context
const THEME = {
light: "light",
dark: "dark",
};
const ThemeContext = React.createContext(THEME.light);
- 使用主题
class ButtonCus extends Component{
render() {
return (
<ThemeContext.Consumer>
{theme => (
<button className={theme}>button</button>
)}
</ThemeContext.Consumer>
);
}
}
现在按钮使用context创建时默认的主题light
,如果想使用dark
主题需要显示提供Provider
进行切换,像这样:
<ThemeContext.Provider value={THEME.dark}>
<ButtonCus/>
</ThemeContext.Provider>
效果:
context的简单使用就是这样
如果每个组件都写一个Consumer,那将是多么痛苦的事。有没有简洁点的不用每次都写Consumer,能不能实现动态切换主题?
答案是肯定的
接下来将切换主题的接口放入context,实现在嵌套层级中切换主题;将Consumer封装在高阶组件中实现简洁的使用Consumer;
- 在顶层将当前应用的主题和切换主题的方法作为context的值向下传递
这里需要将组件状态作为Provider的值传递
class App extends Component{
constructor(props){
super(props);
this.switchTheme = this.switchTheme.bind(this);
//将当前应用的主题和切换主题的方法作为context的值向下传递
this.state = {
theme: THEME.light,
switchTheme: this.switchTheme
};
}
switchTheme() {
this.setState(state => {
return {
theme: state.theme === THEME.light
? THEME.dark
: THEME.light
}
})
}
render(){
return(
<div>
<ThemeContext.Provider value={this.state}>
<ButtonCus/>
<ButtonCus/>
<ButtonCus/>
<ButtonCus/>
</ThemeContext.Provider>
</div>
)
}
}
- 高阶组件封装context的使用逻辑
//高阶组件将contest的使用逻辑提取出来,需要应用主题的组件只需像使用普通props一样使用主题即可
function withContext(Comp) {
return function (props) {
return (
<ThemeContext.Consumer>
{theme => <Comp {...props} theme={theme}/>}
</ThemeContext.Consumer>
)
}
}
- 修改之前的Component 组件
任意组件只要使用withContext包裹后都可以收到名为theme
的属性,将其应用在合适的位置即可。
class ButtonCus extends Component{
render() {
return (
<button
className={this.props.theme.theme}
onClick={this.props.theme.switchTheme}>button
</button>
);
}
}
//使用高阶组件将普通组件应用上主题, 将高阶组件返回的组件赋值为用户命名组件,便于使用
ButtonCus = withContext(ButtonCus);
export {ButtonCus}
到此,点击任意按钮都可以切换全局主题。
后记
context有能力处理全局状态,配合高阶组件简化繁琐的代码,意味着小型应用完全可以使用context处理全局状态。当然redux/mobx管理大型应用状态会更加优秀。