概述
提供组件【 provider 组件 】: 提供给消费组件共享
value
值的父组件消费组件【 consumer 组件 】: 共享提供组件
value
值的所有子组件
React.createContext【创建一个 Context 对象】
当
React
渲染一个订阅了这个Context
对象的consumer
组件,这个组件会从组件树中离自身最近的那个匹配的Provider
中读取到当前的context
值
const MyContext = React.createContext(defaultValue);
说明
- 当组件所属组件树中没有匹配到
Provider
,设置的默认初始值defaultValue
才会生效。 - 如果是将
undefined
传递给Provider
的value
时,默认初始值defaultValue
不会生效。
Context.Provider【可以嵌套使用(内部覆盖外部)】
每个
Context
对象都会返回一个Provider React
组件,它允许消费组件订阅context
的变化
<MyContext.Provider value={ 设置的公共组件需要的 context 的值 }>
// 放置需要公用value值的组件
</MyContext.Provider>
说明
value
属性值:提供给消费组件共享的数据值Provider
的value
值发生变化时,它内部的所有消费组件都会重新渲染Provider
及其内部consumer
组件都不受制于shouldComponentUpdate
函数,因此当consumer
组件在其祖先组件退出更新的情况下也能更新
value
值为对象时,当provider
父组件重新渲染时【value
会被赋予一个新的object
】,可能会引起consumer
子组件不必要的渲染
【解决方法:可以将 value
值提升到 state
状态中管理】
Class.contextType【订阅 context】
// 方法1:
class MyClass extends React.Component {
componentDidMount() {
let value = this.context;
/* 在组件挂载完成后,使用 MyContext 组件的值来执行一些有副作用的操作 */
}
render() {
let value = this.context;
/* 基于 MyContext 组件的值进行渲染 */
}
}
MyClass.contextType = MyContext;
// 方法2: public class fields 语法【实验性语法】
class MyClass extends React.Component {
static contextType = MyContext;
render() {
let value = this.context;
/* 基于这个值进行渲染工作 */
}
}
说明
- 将
React.createContext()
创建的Context
对象赋值给class
的contextType
属性来订阅context
内容 - 订阅
context
后可以在类组件中使用this.context
来获取Provider
组件中定义的value
值,达到组件间的一些数据共享 - 可以在类组件的任何生命周期中访问
this.context
- 订阅多个
context
详情实例见官方文档
Context.Consumer【订阅 context 的变更, 更新 Context 对象中的值】
将共享的
context
设置为对象, 里面可以包含修改对应context
值的方法
import { MyContext } from './theme-context';
function ThemeTogglerButton() {
// Theme Toggler 按钮不仅仅只获取 theme 值,它也从 context 中获取到一个 toggleTheme 函数
return (
<MyContext.Consumer>
{({theme, toggleTheme}) => (
<button onClick={toggleTheme}
style={{backgroundColor: theme.background}}
>
Toggle Theme
</button>
)}
</MyContext.Consumer>
);
}
export default ThemeTogglerButton;
说明
context
为父组件MyContext.Provider
组件的value
属性值【不需要在重新订阅了】customer
组件接受一个函数作为包裹内容,函数参数为对应的provider
组件中设置的共享value
值, 返回值为需要渲染的对应元素
Context.displayName 【定义 MyContext 在 devTool 中显示到名称】
通过给
Context
的属性displayName
赋值来更改在开发工具审查元素中显示的对应元素名称
const MyContext = React.createContext(defaultValue);
MyContext.displayName = 'MyDisplayName';
<MyContext.Provider> // 在 DevTools 中显示为 "MyDisplayName.Provider"
<MyContext.Consumer> // 在 DevTools 中显示为 "MyDisplayName.Consumer"
函数组件中 Context 的使用
使用
useContext
获取context
内容信息
// context.ts
const MyContext = React.createContext(defaultValue);
export default MyContext;
// App.tsx
const [state, setState] = useState({});
<MyContext.Provider value={state}>
<MyComponent />
</MyContext.Provider>
// MyComponent.tsx
import React, { useContext } from 'react';
import MyContext from './context';
const MyComponent = () => {
// 使用 state 展示值,使用 setState 更改值
const { state, setState } = useContext(MyContext);
return (
/* 进行渲染工作 */
)
}
export default MyComponent;
旧 Context API 类组件及函数组件使用
// provider.tsx
class ContextProvider extends React.Component {
constructor(props) {
super(props);
this.state = { value: {} }
}
// 当 state 或者 props 改变的时候,getChildContext 函数就会被调用
getChildContext() {
const { value } = this.state;
return { value, changeValue };
}
// state 中 value 值改变函数
changeValue = (value) => {
this.setState({ value });
}
render() {
return (
<div>{this.props.children}</div>
)
}
}
ContextProvider.childContextTypes = {
value: PropTypes.object
};
// App.tsx
<ContextProvider>
<MyComponent />
</ContextProvider>
// 类子组件 MyComponent.tsx
class MyComponent extends React.Component {
static contextTypes = {
value: PropTypes.object
};
console.log(this.context); // { value: Object, changeValue: Function }
render() {
// 进行渲染工作
}
}
// 函数子组件 MyComponent.tsx
const MyComponent = (props, context) => {
console.log(this.context); // { value: Object, changeValue: Function }
return (
// 进行渲染工作
)
}
MyComponent.contextTypes = {
value: PropTypes.object
};