Context 提供了一个无需为每层组件手动添加 props,就能在组件树间进行数据传递的方法。
const MyContext = React.createContext(defaultValue);
只有当组件所处的树中没有匹配到 Provider
时,其 defaultValue
参数才会生效。这有助于在不使用 Provider
包装组件的情况下对组件进行测试。注意:将 undefined
传递给 Provider
时,消费组件的 defaultValue
不会生效。
import React, { Component } from 'react';
const ThemeContext = React.createContext('light');
class App extends Component {
render() {
return (
<div>
<Toolbar />
</div>
);
}
}
function Toolbar (props) {
return (
<div>
<ThemeButton />
</div>
)
}
class ThemeButton extends Component {
static contextType = ThemeContext
render() {
console.log(this.context) // light
return (
<button>{this.context}</button>
);
}
}
export default App;
import React, { Component } from 'react';
const ThemeContext = React.createContext('light');
class App extends Component {
render() {
return (
<ThemeContext.Provider>
<Toolbar />
</ThemeContext.Provider>
);
}
}
function Toolbar (props) {
return (
<div>
<ThemeButton />
</div>
)
}
class ThemeButton extends Component {
static contextType = ThemeContext
render() {
console.log(this.context) // undefined
return (
<button>{this.context}</button>
);
}
}
export default App;
Provider
接收一个 value
属性,传递给消费组件。
import React, { Component } from 'react';
const ThemeContext = React.createContext('light');
class App extends Component {
render() {
return (
<ThemeContext.Provider value="dark">
<Toolbar />
</ThemeContext.Provider>
);
}
}
function Toolbar (props) {
return (
<div>
<ThemeButton />
</div>
)
}
class ThemeButton extends Component {
static contextType = ThemeContext
render() {
console.log(this.context) // dark
return (
<button>{this.context}</button>
);
}
}
export default App;
一个 Provider
可以和多个消费组件有对应关系。
import React, { Component } from 'react';
const ThemeContext = React.createContext('light');
class App extends Component {
render() {
return (
<div>
<ThemeContext.Provider value='dark'>
<Toolbar />
</ThemeContext.Provider>
</div>
);
}
}
function Toolbar (props) {
return (
<div>
<ThemeButton />
<ThemeButton />
</div>
)
}
class ThemeButton extends Component {
static contextType = ThemeContext
render() {
console.log(this.context) // dark
return (
<button>{this.context}</button>
);
}
}
export default App;
多个 Provider
也可以嵌套使用,里层的会覆盖外层的数据。
import React, { Component } from 'react';
const ThemeContext = React.createContext('light');
class App extends Component {
render() {
return (
<div>
<ThemeContext.Provider value='dark1'>
<Toolbar />
<ThemeContext.Provider value='dark2'>
<Toolbar />
</ThemeContext.Provider>
</ThemeContext.Provider>
</div>
);
}
}
function Toolbar (props) {
return (
<div>
<ThemeButton />
</div>
)
}
class ThemeButton extends Component {
static contextType = ThemeContext
render() {
return (
<button>{this.context}</button>
);
}
}
export default App;
当 Provider
的 value
值发生变化时,它内部的所有消费组件都会重新渲染。Provider
及其内部 consumer
组件都不受制于 shouldComponentUpdate
函数
import React, { Component } from 'react';
const ThemeContext = React.createContext('light');
class App extends Component {
constructor (props) {
super(props);
this.state = {
theme: 'dark'
}
}
change = () => {
this.setState({
theme: 'light'
})
}
render() {
return (
<div>
<ThemeContext.Provider value={this.state.theme}>
<Toolbar />
</ThemeContext.Provider>
<button onClick={this.change}>change</button>
</div>
);
}
}
function Toolbar (props) {
return (
<div>
<ThemeButton />
</div>
)
}
class ThemeButton extends Component {
static contextType = ThemeContext
shouldComponentUpdate () {
console.log('无法控制组件')
return false
}
render() {
return (
<button>{this.context}</button>
);
}
}
export default App;
挂载在 class
上的 contextType
属性会被重赋值为一个由 React.createContext()
创建的 Context
对象。这能让你使用 this.context
来消费最近 Context
上的那个值。你可以在任何生命周期中访问到它,包括 render
函数中。
import React, { Component } from 'react';
const ThemeContext = React.createContext('light');
class App extends Component {
render() {
return (
<div>
<ThemeContext.Provider value='dark'>
<Toolbar />
</ThemeContext.Provider>
</div>
);
}
}
function Toolbar (props) {
return (
<div>
<ThemeButton />
</div>
)
}
class ThemeButton extends Component {
render() {
return (
<button>{this.context}</button>
);
}
}
ThemeButton.contextType = ThemeContext
export default App;
这能让你在函数式组件中完成订阅 context
。这需要函数作为子元素(function as a child)这种做法。这个函数接收当前的 context
值,返回一个 React 节点。传递给函数的 value
值等同于往上组件树离这个 context
最近的 Provider
提供的 value
值。如果没有对应的 Provider
,value
参数等同于传递给 createContext()
的 defaultValue
。
import React, { Component } from 'react';
const ThemeContext = React.createContext('light');
class App extends Component {
render() {
return (
<div>
<ThemeContext.Provider value='dark'>
<Toolbar />
</ThemeContext.Provider>
</div>
);
}
}
function Toolbar (props) {
return (
<div>
<ThemeButton />
</div>
)
}
function ThemeButton () {
return (
<ThemeContext.Consumer>
{
(value) => (<button>{value}</button>)
}
</ThemeContext.Consumer>
)
}
export default App;