blog
blog copied to clipboard
全新的 React Context API
在一个经典的
React
应用中,组件之间通信是常用到的技术方案。在父子组件之间通常通过props
来传递参数,而非父子组件就比较麻烦了,要么就一级一级通过props
传递,要么就使用Redux
orMobx
这类状态管理的状态管理库,但是这样无疑增加了应用的复杂度。在 FEers 的期盼中,React
团队终于从16.3.0
版本开始新增了一个新的 APIContext
,福音啊。好了,今天我就来一起学习一下这个新的Context
。
什么时候使用 Contsxt
Context 目的是为了共享可以被认为是 React
组件“全局”树的数据。例如当前应用的主题、首选语言等等。接下来看看通过 props
和 Context
两种方式实现按钮组件样式参数传递方式的对比:
- props
class App extends React.Component {
render() {
return <Toolbar theme="dark" />;
}
}
Toolbar(props) {
return (
<div>
<ThemedButton theme={props.theme} />
</div>
);
}
ThemedButton(props) {
return <Button theme={props.theme} />;
}
- Context
// 创建 context 实例
const ThemeContext = React.createContext('light');
class App extends React.Component {
render() {
return (
<ThemeContext.Provider value="dark">
<Toolbar />
</ThemeContext.Provider>
);
}
}
Toolbar(props) {
return (
<div>
<ThemedButton />
</div>
);
}
ThemedButton(props) {
return (
<ThemeContext.Consumer>
{theme => <Button {...props} theme={theme} />}
</ThemeContext.Consumer>
);
}
API
React.createContext
创建一个 Context
,React.createContext
提供了 {Provider,Comsumer}
两个方法,上面的代码也可以这个来写:
const {Provider,Comsumer} = React.createContext('light');
class App extends React.Component {
render() {
return (
<Provider value="dark">
{/* ... */}
</Provider>
);
}
}
{/* ... */}
ThemedButton(props) {
return (
<Consumer>
{/* ... */}
</Consumer>
);
}
Provider
这里的 Provider
类似 react-redux
中的 Provider
组件,用来注入全局的 data
(允许 Consumer
订阅 Context
的变化)。一个 Provider
可以连接到多个 Consumer
。
Consumer
Consumer
组件,表示要消费 Provider
传递的数据(订阅 Context
的响应组件)。当 Provider
发生变化的时候,所有的 Consumer
都会被 re-rendered
。
结束语
新 Context
的引入,一定程度上可以减少不少项目对 redux
全家桶的依赖,从而降低了项目的复杂程度,何乐而不为呢~~
React 16+ 新的生命周期
consumer 好像并没能订阅 context 的变化,只能获取初始值,是不是我用的不对? 我是这样用的: 在父组件:
import Child1 from './child1'
const defaultContext = {
a: 0,
setA: function (a) {
this.a = a
}
}
export const Context = createContext()
export default class Father extends React.Component {
render() {
return <Context.Provider value={defaultContext}>
<Child1/>
</Context.Provider>
}
}
在子组件:
class Child1 extends React.Component {
render() {
const {context} = this.props
return<div style={{backgroundColor: '#897', padding: '29px'}}>
子组件1
<div>a:{context.a}</div>
<input placeholder='输入' onChange={(e) => context.setA(e.target.value)}></input>
</div>
}
}
export default () => <Context.Consumer>{
(context) => {
return <Child1 context={context}/>
}
}</Context.Consumer>
我在子组件中调用 context.setA()
修改了 context.a
,但是子组件并没有更新
知道为啥子组件没有更新了,因为组件更新需要 state / props 变化,但是 context value 这两者都不是