React
中使⽤
Context
实现祖代组件向后代组件跨层级传值。 Vue中的
provide & inject
来源于
Context
Context API
React.createContext
创建⼀个
Context
对象。当
React
渲染⼀个订阅了这个Context 对象的组件,这个组件会从组件树中离⾃身最近的那个匹配Provider
中读取到当前的
context
值。
Context.Provider
Provider
接收⼀个
value
属性,传递给消费组件,允许消费组件订阅 context
的变化。⼀个
Provider
可以和多个消费组 件有对应关系。多个 Provider
也可以嵌套使⽤,⾥层的会覆 盖外层的数据。 当 Provider
的
value
值发⽣变化时,它内部的所有消费组 件都会重新渲染。Provider
及其内部
consumer
组件都不受 制于 shouldComponentUpdate
函数,因此当
consumer
组 件在其祖先组件退出更新的情况下也能更新。
Class.contextType
挂载在
class
上的
contextType
属性会被重赋值为⼀个由
React.createContext()
创建的
Context
对象。这能让你 使⽤ this.context
来消费最近
Context
上的那个值。你可 以在任何⽣命周期中访问到它,包括 render
函数中。
Context.Consumer
这⾥,
React
组件也可以订阅到
context
变更。这能让你在
函 数式组件
中完成订阅
context。
这个函数接收当前的
context
值,返回⼀个
React
节点。传
递给函数的
value
值等同于往上组件树离这个
context
最近
的
Provider
提供的
value
值。如果没有对应的
Provider
,
value
参数等同于传递给
createContext()
的 defaultValue。
使⽤
Context
创建
Context =>
获取
Provider
和
Consumer => Provider
提供 值 => Consumer
消费值
范例:共享主题⾊
import React, {Component} from "react";
import {ThemeProvider} from "../themeContext";
import ContextTypePage from"./ContextTypePage";
import ConsumerPage from "./ConsumerPage";
class ContextPage extends Component {
constructor(props) {
super(props);
this.state = {
theme: {
themeColor: "red"
}
};
}
changeColor = () => {
const {themeColor} = this.state.theme;
this.setState({
theme: {
themeColor: themeColor === "red" ? "green" : "red"
}
});
};
render() {
const {theme} = this.state;
return (
<div className="App">
{/* 组件跨层级通信 */}
<button onClick= {this.changeColor}>change color</button>
{/* 如果把这⾥的MyProvider注释掉,ContextTypePage和ConsumerPage⾥将取不到theme值,⽽取默认值pink */}
<ThemeProvider value={theme}>
<ContextTypePage />
<ConsumerPage />
</ThemeProvider>
</div>
);
}
}
export default ContextPage;
//themeContext.js
import React from "react";
export const ThemeContext = React.createContext({themeColor: "pink"});
export const ThemeProvider = ThemeContext.Provider;
export const ThemeConsumer = ThemeContext.Consumer;
// pages/ContextTypePage.js
import React, {Component} from "react";
import {ThemeContext} from "../themeContext";
export default class ContextTypePage extends Component {
static contextType = ThemeContext;
render() {
console.log("ContextTypePage",this.context); //sy-log
const {themeColor} = this.context;
return (
<div className="border">
<h3 className= {themeColor}>ContextTypePage</h3>
</div>
);
}
}
// pages/ConsumerPage.js
import React, {Component} from "react";
import {ThemeConsumer} from "../themeContext";
export default class ConsumerPage extends Component {
render() {
return (
<div className="border">
<h3>ConsumerPage</h3>
<ThemeConsumer>{ctx => <HandleTabBar{...ctx} />}</ThemeConsumer>
</div>
);
}
}
function HandleTabBar({themeColor}) {
console.log("themeColor", themeColor); //sylog
return <div className={themeColor}>⽂本</div>;
}
注意:
因为
context
会使⽤参考标识(
reference identity
)来决定 何时进⾏渲染,这⾥可能会有⼀些陷阱,当 provider
的⽗组 件进⾏重渲染时,可能会在 consumers
组件中触发意外的渲 染。
为了防⽌这种情况,将 value 状态提升到⽗节点的 state ⾥。
原文:视频讲解笔记