React 组件跨层级通信 - Context
前言:
如果在页面逻辑很远的两个页面需要进行数据传递,我们会怎么办呢?通过props一层一层的向下传递吗?通过全局变量来传递信息吗?
-
如果使用
props中间需要修改是不是每一层都需要修改,而且一层一层的传递工作量也非常大,比较麻烦; -
如果使用全局变量来传递信息,我们怎么保证数据更新了,它的子组件刷新呢?如果使用
forceUpdate更新组件,很显然就很麻烦,而且全局变量还会造成全局污染;
嗯...孩子大了终究是瞒不住了,接下来我们来介绍一个React组件跨层级通信API context
Context API
-
创建一个Context对象
-
创建Provider,传递value
-
子组件消费value
-
contextType
- 只能用在类组件,只能订阅单一的context来源
-
useContext
- 只能用在函数组件或者自定义hook中
-
consumer
- 不限制函数或者类组件
// context.js
import React from "react";
export const Context = React.createContext();
export const UserContext = React.createContext();
-
1. contextType
// 父组件 ContextPage.js
import React, { Component } from "react";
import { Context } from "../context"; // 引入Context对象
import ContextTypePage from "./ContextTypePage"; // 引入子组件
export default class ContextPage extends Component {
constructor(props) {
super(props);
this.state = {
theme: { themeColor: "red" },
};
}
render() {
const { theme, user } = this.state;
return (
<div>
<h3>ContextPage</h3>
<Context.Provider value={theme}> // 创建Context.Provider,传递value
<ContextTypePage /> // 调用子组件进行消费value
</Context.Provider>
</div> );
}
}
// 子组件 ContextTypePage.js
import React, { Component } from "react";
import { Context, /**UseContext**/ } from "../context"; // 引入Context对象
export default class ContextPage extends Component {
static contextType = Context; // 使用contextType
// 因为contextType只能订阅单一的context来源,所以我们在这里再获取一个UseContext的话,Context将失效
// static contextType = UseContext;
render() {
const { themeColor } = this.context;
return (
<div>
<h3 className={themeColor}>ContextTypePage</h3>
</div>
);
}
}
2. useContext
// 父组件 ContextPage.js
import React, { Component } from "react";
import { Context, UserContext } from "../context"; // 引入Context对象和UserContext对象
import ContextTypePage from "./ContextTypePage"; // 引入子组件
import UseContextPage from "./UseContextPage"; // 引入子组件
export default class ContextPage extends Component {
constructor(props) {
super(props);
this.state = {
theme: { themeColor: "red" },
user: { name: "xiaoming" },
};
}
render() {
const { theme, user } = this.state;
return (
<div>
<h3>ContextPage</h3>
<Context.Provider value={theme}>
<UserContext.Provider value={user}> // UserContext.Provider,传递value
<ContextTypePage />
<UseContextPage /> // 消费子组件
</UserContext.Provider>
</Context.Provider>
</div>
);
}
}
// 子组件 UseContextPage.js
import React from "react";
import { Context, UserContext } from "../context";
export default function UseContextPage(props) { // 只能在函数组件中或者自定义hook中使用
// 可以多个订阅
const theme = React.useContext(Context);
const user = React.useContext(UserContext);
return (
<div>
<h3 className={theme.themeColor}>UseContextPage</h3>
<p>{user.name}</p>
</div>
);
}
3. consumer
// 父组件 ContextPage.js
import React, { Component } from "react";
import { Context, UserContext } from "../context";
import ContextTypePage from "./ContextTypePage";
import UseContextPage from "./UseContextPage";
import ConsumerPage from "./ConsumerPage"; // 引入子组件
export default class ContextPage extends Component {
constructor(props) {
super(props);
this.state = {
theme: { themeColor: "red" },
user: { name: "xiaoming" },
};
}
render() {
const { theme, user } = this.state;
return (
<div>
<h3>ContextPage</h3>
<Context.Provider value={theme}>
<UserContext.Provider value={user}>
<ContextTypePage />
<UseContextPage />
<ConsumerPage /> // 子组件消费value
</UserContext.Provider>
</Context.Provider>
</div>
);
}
}
// 子组件 ConSumerPage.js
import React, { Component } from "react";
import { Context, UserContext } from "../context";
export default class ConsumerPage extends Component {
render() {
return (
<div>
<h3>ContextPage</h3>
<Context.Consumer> // 创建Context.Consumer对象
{(theme, user) => {
return (
<div className={theme.themeColor}>
<UserContext.Consumer>
{(user) => {
return <div>{user.name}</div>;
}}
</UserContext.Consumer>
</div>
);
}}
</Context.Consumer>
</div>
);
}
}