非父子组件数据的共享:
import React, { Component } from 'react';
function ProfileHeader(props) {
return (
<div>
<h2>用户昵称: {props.nickname}</h2>
<h2>用户等级: {props.level}</h2>
</div>
)
}
class Profile extends Component {
render() {
return (
<div>
<ProfileHeader nickname={this.props.nickname} level={this.props.level} />
<ul>
<li>设置1</li>
<li>设置2</li>
<li>设置3</li>
<li>设置4</li>
<li>设置5</li>
</ul>
</div>
)
}
}
export default class App extends Component {
constructor() {
super();
this.state = {
nickname: "coderwhy",
level: 99
}
}
render() {
const { nickname, level } = this.state;
return (
<div>
<Profile nickname={nickname} level={level} />
<h2>其他内容</h2>
</div>
)
}
}
两种写法是等价的:
function App1() {
return <Greeting firstName="Ben" lastName="Hector" />;
}
function App2() {
const props = {firstName: 'Ben', lastName: 'Hector'};
return <Greeting {...props} />;
}
上面的Profile的传递代码可以修改为如下代码:
<ProfileHeader {...this.props}/>
但是,如果层级更多的话,一层层传递是非常麻烦,并且代码是非常冗余的:
const MyContext = React.createContext(defaultValue);
创建一个需要共享的Context对象:
<MyContext.Provider value={/* 某个值 */}>
每个 Context 对象都会返回一个 Provider React 组件,它允许消费组件订阅 context 的变化:
当 Provider 的 value 值发生变化时,它内部的所有消费组件都会重新渲染;
Class.contextType
class MyClass extends React.Component {
componentDidMount() {
let value = this.context;
/* 在组件挂载完成后,使用 MyContext 组件的值来执行一些有副作用的操作 */
}
componentDidUpdate() {
let value = this.context;
/* ... */
}
componentWillUnmount() {
let value = this.context;
/* ... */
}
render() {
let value = this.context;
/* 基于 MyContext 组件的值进行渲染 */
}
}
MyClass.contextType = MyContext;
挂载在 class 上的 contextType 属性会被重赋值为一个由 React.createContext() 创建的 Context 对象:
Context.Consumer
<MyContext.Consumer>
{value => /* 基于 context 值进行渲染*/}
</MyContext.Consumer>
这里,React 组件也可以订阅到 context 变更。这能让你在 函数式组件 中完成订阅 context。
举个栗子:
import React, { Component } from 'react';
const UserContext = React.createContext({ nickname: "默认", level: -1 })
class ProfileHeader extends Component {
render() {
return (
<div>
<h2>用户昵称: {this.context.nickname}</h2>
<h2>用户等级: {this.context.level}</h2>
</div>
)
}
}
ProfileHeader.contextType = UserContext;
class Profile extends Component {
render() {
return (
<div>
<ProfileHeader />
<ul>
<li>设置1</li>
<li>设置2</li>
<li>设置3</li>
<li>设置4</li>
<li>设置5</li>
</ul>
</div>
)
}
}
export default class App extends Component {
render() {
return (
<div>
<UserContext.Provider value={{ nickname: "why", level: 99 }}>
<Profile />
</UserContext.Provider>
<h2>其他内容</h2>
</div>
)
}
}
并没有作为 UserContext.Provider 的子组件:使用默认值defaultValue
什么时候使用Context.Consumer呢?
如下栗子:
当使用value的组件是一个函数式组件时;
function ProfileHeader(props) {
return (
<div>
<UserContext.Consumer>
{value => {
return (
<div>
<h2>用户昵称: {value.nickname}</h2>
<h2>用户等级: {value.level}</h2>
</div>
)
}}
</UserContext.Consumer>
</div>
)
}
当组件中需要使用多个Context时;
1.创建一个新的Context
const ThemeContext = React.createContext({ color: "black" });
2.Provider的嵌套
<UserContext.Provider value={{ nickname: "why", level: 99 }}>
<ThemeContext.Provider value={{color: "red"}}>
<Profile />
</ThemeContext.Provider>
</UserContext.Provider>
3.使用Consumer的嵌套
<UserContext.Consumer>
{value => {
return (
<ThemeContext.Consumer>
{
theme => (
<div>
<h2 style={theme}>用户昵称: {value.nickname}</h2>
<h2 style={theme}>用户等级: {value.level}</h2>
</div>
)
}
</ThemeContext.Consumer>
)
}}
</UserContext.Consumer>