组件跨层级通信 - Context
一.概念
Context 提供了一个无需为每层组件手动添加props,就能在组件树间进行数据传递的方法。
二.API
- React.createContext
const MyContext = React.createContext(defaultValue);
- Context.Provider
<MyContext.Provider value={/* 某个值 */}>
- Class.contextType(只能用在类组件上,只能订阅单一contextType)
class MyClass extends React.Component {
static contextType = MyContext;
render() {
let value = this.context;
/* 基于这个值进行渲染工作 */
}
}
- Context.Consumer
<MyContext.Consumer>
{value => /* 基于 context 值进行渲染*/}
</MyContext.Consumer>
- useContext(hook方法,只能用在function组件当中,或者自定义hook中)
三.实际项目中的使用
- 新建一个文件---src/Contenxt.js,用于定义createContext,Provider,Consumer
import React from "react";
export const ThemeContext = React.createContext({themeColor: "pink"});
export const ThemeProvider = ThemeContext.Provider;
export const ThemeConsumer = ThemeContext.Consumer;
export const UserContext = React.createContext();
export const UserProvider = UserContext.Provider;
export const UserConsumer = UserContext.Consumer;
- 在页面引入---src/pages/ContextPage.js,并提供value
import React, {Component} from "react";
import {ThemeProvider, UserProvider, UserContext} from "../Context";
import ConsumerPage from "./ConsumerPage";
import UseContextPage from "./UseContextPage";
export default class ContextPage extends Component {
constructor(props) {
super(props);
this.state = {
theme: {
themeColor: "red"
},
user: {name: "曾小白"}
};
}
render() {
const {theme, user} = this.state;
return (
<div>
<h3>ContextPage</h3>
<ThemeProvider value={theme}>
<UserProvider value={user}>
<ConsumerPage />
<UseContextPage />
</UserProvider>
</ThemeProvider>
</div>
);
}
}
- 在页面中接收---src/pages/ConsumerPage.js,接收value
import React, {Component} from "react";
import {ThemeConsumer, UserConsumer} from "../Context";
export default class ConsumerPage extends Component {
render() {
return (
<div>
<h3>ConsumerPage</h3>
<ThemeConsumer>
{themeContext => (
<div className={themeContext.themeColor}>
omg
<UserConsumer>
{userContext => <Child {...userContext} />}
</UserConsumer>
</div>
)}
</ThemeConsumer>
</div>
);
}
}
function Child(props) {
return <div>{props.name}</div>;
}
- 在function中使用---src/pages/UseContextPage.js,使用useContext
import React, {useContext} from "react";
import {ThemeContext, UserContext} from "../Context";
export default function UseContextPage(props) {
const {themeColor} = useContext(ThemeContext);
const {name} = useContext(UserContext);
return (
<div className="border">
<h3 className={themeColor}>UseContextPage</h3>
<p>{name}</p>
</div>
);
}
注意
当 provider 的父组件进行重渲染时,可能会在 consumers 组件中触发意外的渲染 举个栗子,当每一次 Provider 重渲染时,以下的代码会重渲染所有下面的 consumers 组件,因为 value 属性总是被赋值 为新的对象:
class App extends React.Component {
render() {
return (
<Provider value={{something: 'something'}}>
<Toolbar />
</Provider>
); }
}
为了防止这种情况,将 value 状态提升到父节点的 state 里
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
value: {something: 'something'},
};
}
render() {
return (
<Provider value={this.state.value}>
<Toolbar />
</Provider>
);
}
}
总结
- 后面我们要学习到的react-redux的 ,就是通过 Context提供一个全局态的 store ,
- 路由组件react-router通过 Context 管理路由状态等等。