「这是我参与11月更文挑战的第24天,活动详情查看:2021最后一次更文挑战」。
本文是自己学习
useContext
的笔记。
1. 两组件通信
React 中,父子组件需要通信时,父组件可以将参数写在props
中传递给子组件,实现父组件向子组件通信;父组件还可以传递一个函数给子组件,子组件调用这个函数,实现子组件向父组件的通信。这就完成了父子组件的相互通信。
但当组件嵌套关系复杂的时候,如下图所示,A
组件下有B
组件和C
组件,B
组件下有D
组件,C
组件下有E
组件。
当需要在A
组件和D
组件之间通信时,也可以采取上述的方法,A
通过props
一层一层传递参数到D
组件,D
组件再调用函数,一层一层返回到A
组件。
2. Context
但当组件嵌套关系更复杂时,这样的方式极其繁琐,且不易维护。这里介绍一种使用Context
实现组件通信的方式。
Context 提供了一个无需为每层组件手动添加 props,就能在组件树间进行数据传递的方法。
使用Context
,可以避免通过中间组件传递props
。有的时候在组件树中很多不同层级的组件需要访问同一批数据。Context
能让你将这些数据向组件树下所有的组件进行广播,所有的组件都能访问到这些数据,也能访问到后续的数据更新。
3. useContext 实践
首先实现上述关系的组件:
要实现的效果为,E
组件中点击add
,会增加计数值。点击D
组件的clear
按钮,会对E
组件的计数值进行清零。
A
组件中,需要从react
中导入createContext
方法,在组件外部创建Context对象,并导出。同时,需要用<MyContext.Provider></MyContext.Provider>
进行包裹,其中,MyContext
是自定义的名称。数据对象放在<MyContext.Provider>
的value
中。这样,被包裹的所有组件,都能直接拿到这两个参数了。
import { createContext, useState } from 'react';
import B from './B';
import C from './C';
import './index.css';
// 在组件外部创建Context对象,并导出
export const MyContext = createContext();
const A = () => {
const [count, setCount] = useState(0);
return (
// 数据对象放在value中,向下传递
<MyContext.Provider value={{ count, setCount }}>
A组件
<B />
<C />
</MyContext.Provider>
);
};
export default A;
复制代码
E
组件需要从A
中引入创建的context
对象MyContext
,并使用useContext
方法,从MyContext
中拿到其中的参数。
// 引入创建的context
import { MyContext } from './A';
import { useContext } from 'react';
const E = () => {
// 拿到两个参数
const { count, setCount } = useContext(MyContext);
return (
<div>
我是E, 计数值:{count}
<button onClick={() => setCount(count => count + 1)}>add</button>
</div>
);
};
export default E;
复制代码
D
组件也需要从A
中引入创建的context
对象MyContext
,使用useContext
方法,拿到setCount
方法。
// 引入创建的context
import { MyContext } from './A';
import { useContext } from 'react';
const D = () => {
// 拿到参数
const { setCount } = useContext(MyContext);
return (
<div>
我是D
<button onClick={() => setCount(0)}>clear</button>
</div>
);
};
export default D;
复制代码
这样,E
组件和D
组件使用的是同一批数据,也能访问到这些数据的更新,实现了跨组件通信。
4. 集中式管理 Context 对象
如果一个项目中,多处使用context
,会造成代码结构不清晰,不便于维护。这时可以将所有创建context
的代码,放入到专门的文件中,进行集中管理,需要用到的地方,都从此文件引入即可。
例如,将创建的所有Context
对象放入contextManager.js
中,并导出:
// contextManager.js
import { createContext } from 'react';
export const MyContext = createContext();
// 定义的其他context
export const MyContext2 = createContext();
export const MyContext3 = createContext();
复制代码