Context
Context 提供了一种方式,能够让数据在组件数中传递而不必一级一级手动传递,可以把 Context 开成是一种全局变量
其实 Context 是 Provider (生产者) 和 Consumer (消费者)共同来实现的,通过这两个标签我们可以使用 Context
React.createContext
const MyContext = React.createContext(defaultValue);
该代码创建了一个 Context 对象。当 React 渲染一个订阅了这个 Context 对象的组件,这个组件会从组件树中离自身最近的那个匹配的 Provider
中读取到当前的 context 值。
只有当组件所处的树中没有匹配到 Provider 时,也就是没有Context.Provider
,其 defaultValue
参数才会生效。一般我们的业务中是不会用到这个特性的,但是做单元测试的时候这个特性很有用
Context.Provider
<MyContext.Provider value={/* 某个值 */}>
</MyContext.Provider>
每个 Context 对象都会返回一个 Provider React 组件,它允许消费组件订阅 context 的变化。
Provider 接收一个 value
属性,传递给消费组件。一个 Provider 可以和多个消费组件有对应关系。多个 Provider 也可以嵌套使用,里层的会覆盖外层的数据。
当 Provider 的 value
值发生变化时,它内部的所有消费组件都会重新渲染。Provider 及其内部 consumer 组件都不受制于 shouldComponentUpdate
函数,因此当 consumer 组件在其祖先组件退出更新的情况下也能更新
Context.Consumer
<Context.Consumer>
{value => /* 基于 context 值进行渲染,这里写的是一些jsx */}
</Context.Consumer>
这里,React 组件也可以订阅到 context 变更。这能让你在函数式组件中完成订阅 context。
这需要函数作为子元素(function as a child)这种做法。这个函数接收当前的 context 值,返回一个 React 节点。传递给函数的 value
值等同于往上组件树离这个 context 最近的 Provider 提供的 value
值。如果没有对应的 Provider,value
参数等同于传递给 createContext()
的 defaultValue
实例:
import React,{createContext, Component} from 'react';
import './App.css';
const BatteryContest = createContext(90); // 默认值是 90,当 <BttryContest.Provider> 标签不提供时,使用默认值
// 多个 context
const OnlineContest = createContext();
class Middle extends Component{
render(){
return (
<div>
<h1>middle</h1>
<Leaf/>
</div>
)
}
}
class Leaf extends Component {
// 多个 contest 嵌套
render(){
return (
<BatteryContest.Consumer>
{
x => (
<OnlineContest.Consumer>
{
online => <h1>Battery: {x}, Online: {String(online)}</h1>
}
</OnlineContest.Consumer>
)
}
</BatteryContest.Consumer>
)
}
}
class App extends Component{
state = {
battery: 60,
online: false,
}
render(){
const {battery,online} = this.state;
return (
<BatteryContest.Provider value={battery}>
<OnlineContest.Provider value={online}>
<button
type="button"
onClick={() => {