React 中 Context 用法详解
Context 的创建
API: const MyContext = React.createContext(initialValue)
- initialValue:
context
初始值 - 返回值
- MyContext.Provider: 提供者,是一个 React 组件,使用
Provider
标签包裹后的组件,自身以及后代组件都可以访问到MyContext
的值 - MyContext.Consumer: 消费者,是 React 组件,使用
Consumer
包裹后,可以使用render props
的方式渲染内容,获取到MyContext
的值
- MyContext.Provider: 提供者,是一个 React 组件,使用
1import React from \"react\";
2
3const defaultTheme = { color: \"black\" };
4
5const ThemeContext = React.createContext(defaultTheme);
Context.Provider 的使用
每个 Context 对象都会返回一个 Provider React 组件,它允许消费组件订阅 context 的变化。
使用一个 Provider 来将当前的 context 传递给以下的组件树,无论多深,任何组件都能读取这个值。
接受一个属性 value,子组件中获取到的 context 值就是 value 值
- 单个
Provider
使用
1function App() {
2 return (
3 <ThemeContext.Provider value={{ color: \"blue\" }}>
4 <p>Hello World</p>
5 </ThemeContext.Provider>
6 );
7}
- 多个
Provider
使用
1function App() {
2 const [count, setCount] = useState(0);
3 return (
4 <ThemeContext.Provider value={{ color: \"blue\" }}>
5 <CounterContext.Provider value={{ count, setCount }}>
6 <p>Hello World</p>
7 </CounterContext.Provider>
8 </ThemeContext.Provider>
9 );
10}
动态 Context
Context.Provider 不仅可以设置 value,也可以动态的修改 value 当 value 值发生变化的时候,所有依赖改 Context 的子组件都会进行渲染
- 创建动态 CounterContext
1const defaultTheme = { color: \"black\" };
2const defaultCounter = {
3 count: 1,
4 setCount: () => {},
5};
6
7const ThemeContext = React.createContext(defaultTheme);
8
9const CounterContext = React.createContext(defaultCounter);
- 将修改 value 的方法作为 value 的属性传递下去
1function App() {
2 const [count, setCount] = useState(0);
3 return (
4 <ThemeContext.Provider value={{ color: \"blue\" }}>
5 <CounterContext.Provider value={{ count, setCount }}>
6 <p>App 页面 count: {count}</p>
7 <ContextType />
8 <HookContext />
9 <ConsumerContext />
10 </CounterContext.Provider>
11 </ThemeContext.Provider>
12 );
13}
- 在子组件中调用修改 value 的方法
1export default function HookContext() {
2 const { color } = useContext(ThemeContext);
3 const { count, setCount } = useContext(CounterContext);
4 return (
5 <>
6 <h2 style={{ color }}>useContext 使用</h2>
7 <p>
8 <div>HookContext 页面 count: {count}</div>
9 <button onClick={() => setCount(count + 1)}>increment</button>
10 </p>
11 </>
12 );
13}
消费 Context 值
- static contextType
- Context.Consumer
- useContext
Class.contextType
- 在类组件中设置静态属性 contextType 为某个 Context
- 在使用的时候通过 this.context 获取到 Context 的值
1export default class ContextType extends Component {
2 static contextType = ThemeContext;
3 render() {
4 const { color } = this.context;
5 return <h2 style={{ color }}>ContextType 使用</h2>;
6 }
7}
Context.Consumer
Context.Consumer 是一个 React 组件可以订阅 context 的变更,既可以在函数组件中使用也可以在类组件中使用
这种方法需要一个函数作为子元素(function as a child)。这个函数接收当前的 context 值,并返回一个 React 节点。
传递给函数的 value 值等等价于组件树上方离这个 context 最近的 Provider 提供的 value 值。如果没有对应的 Provider,value 参数等同于传递给 createContext() 的 defaultValue
- 消费一个 Context
1export default function ConsumerContext() {
2 return (
3 <ThemeContext.Consumer>
4 {(theme) => {
5 const { color } = theme;
6 return <h2 style={{ color }}>Context.Consumer</h2>;
7 }}
8 </ThemeContext.Consumer>
9 );
10}
- 消费多个 Context
1export default function ConsumerContext() {
2 return (
3 <ThemeContext.Consumer>
4 {(theme) => (
5 <CounterContext.Consumer>
6 {(context) => {
7 const { color } = theme;
8 const { count } = context;
9 return (
10 <>
11 <h2 style={{ color }}>Context.Consumer</h2>
12 <p>ConsumerContext 页面 count: {count}</p>
13 </>
14 );
15 }}
16 </CounterContext.Consumer>
17 )}
18 </ThemeContext.Consumer>
19 );
20}
useContext
通过 useContext 可以获取到 value 值,参数是对应的 Context
可以再一个组件中使用多次 useContext 获取多个 Context 对应的 value 值
1export default function HookContext() {
2 const { color } = useContext(ThemeContext);
3 const { count, setCount } = useContext(CounterContext);
4 return (
5 <>
6 <h2 style={{ color }}>useContext 使用</h2>
7 <p>
8 <div>HookContext 页面 count: {count}</div>
9 <button onClick={() => setCount(count + 1)}>increment</button>
10 </p>
11 </>
12 );
13}
displayName
context 对象接受一个名为 displayName 的 property,类型为字符串。React DevTools 使用该字符串来确定 context 要显示的内容。
示例,下述组件在 DevTools 中将显示为 MyDisplayName:
1const MyContext = React.createContext(/* some value */);
2MyContext.displayName = \'MyDisplayName\';
3
4<MyContext.Provider> // \"MyDisplayName.Provider\" 在 DevTools 中
5<MyContext.Consumer> // \"MyDisplayName.Consumer\" 在 DevTools 中
总结
- 创建 Context: const MyContext = React.createContext(defaultValue)
- 使用 Context.Provider 组件将子组件进行包裹,则无论子组件层级多深,都可以获取到对应的 value 值
- 使用 Class.contextType 的方式获取 Context,可以在组件中通过 this.context 的方式获取到对应的 value 值
- 只能在类组件中使用
- 组件中只能使用一个 Context
- 使用 Context.Consumer 组件消费 Context
- 需要一个函数作为子元素,函数参数是距离最近的 Context 的 value 值,返回一个组件
- 可以在类组件中使用也可以在函数组件中使用
- 可以消费多个 Context
- 使用 useContext 消费 Context
- 只能在函数组件中使用
- 可以通过调用多次 useContext 消费多个 Context
- Context.Provider 中的 value 发生变化,则依赖当前 Context 的子组件都会发生进行更新
上一篇:
组建库开发
相关笔记