React(react18)中组件通信03——简单使用 Context 深层传递参数
- 1. 前言
- 1.1 React中组件通信的其他方式
- 1.2 引出 Context
- 2. 简单例子
- 3. 语法说明
- 3.1 createContext(defaultValue)
- 3.2 value
- 3.3 useContext(SomeContext)
- 4. 总结
- 4.1 Context
- 4.1.1 Context 小总结
- 4.1.2 Context 应用场景
- 4.1.3 Context-官网
- 4.2 createContext
- 4.3 useContext()
- 5. 附代码
1. 前言
1.1 React中组件通信的其他方式
- React(react18)中组件通信01——props.
- React(react18)中组件通信02——消息订阅与发布、取消订阅以及卸载组件时取消订阅.
1.2 引出 Context
- 需求场景:
- 我们知道,如果父传子,可以通过props,如果子再传孙,还可以通过props,但是如果家族庞大,组件关系如果一颗大树,一直向下传递,这时候如果还用props,明显就显得有点费劲了。
- 而且如果这个参数子不要孙要的情况,通过props逐层传递也不是很合理。
- 再或者,如果这个后代离根太远了,如果还用props逐层传递下去,那么传递 props 会变的十分冗长和不便。
- 这就需要考虑怎么能跳过中间代还能给后后代传递呢?这就需要接下来要介绍的Context了……
- 我们知道,如果父传子,可以通过props,如果子再传孙,还可以通过props,但是如果家族庞大,组件关系如果一颗大树,一直向下传递,这时候如果还用props,明显就显得有点费劲了。
- 使用 Context 可以深层传递参数,它可以在组件树中不需要 props 将数据“直达”到所需的组件中,看官网介绍:
2. 简单例子
- 先看实现的效果,如下是:爷爷组件给孙组件传消息:
- 代码设计——目录结构
- 代码设计——代码实现
- context.js + App.js + index.js
- Parent.jsx + Child.jsx + GrandSon.jsx
- context.js + App.js + index.js
3. 语法说明
3.1 createContext(defaultValue)
- 如下:
3.2 value
value
:该值为你想传递给所有处于这个 provider 内读取该 context 的组件,无论它们处于多深的层级。context 的值可以为任何类型。该 provider 内的组件可通过调用 useContext(SomeContext) 来获取它上面最近的 context provider 的 value。
3.3 useContext(SomeContext)
- 在组件的顶层调用 useContext 来读取和订阅 context。
4. 总结
4.1 Context
4.1.1 Context 小总结
- Context 使组件向其下方的整个树提供信息。
- 传递 Context 的方法:
- 通过
export const MyContext = createContext(defaultValue)
创建并导出 context。 - 在无论层级多深的任何子组件中,把 context 传递给
useContext(MyContext)
Hook 来读取它。 - 在父组件中把 children 包在
<MyContext.Provider value={...}
> 中来提供 context。
- 通过
- Context 会穿过中间的任何组件。
- Context 可以让你写出 “较为通用” 的组件。
- 在使用 context 之前,先试试传递 props 或者将 JSX 作为 children 传递。
4.1.2 Context 应用场景
- 看官网介绍:
4.1.3 Context-官网
- 如下:
https://zh-hans.react.dev/learn/passing-data-deeply-with-context.
4.2 createContext
- 上下文使得组件能够无需通过显式传递参数的方式 将信息逐层传递。
- 在任何组件外调用 createContext 来创建一个或多个上下文。
因为,通常,来自不同文件的组件都会需要读取同一个 context。因此,在一个单独的文件内定义 context 便成了常见做法。你可以使用 export 语句 将其导出,以便其他文件读取使用 - 参考官网:
https://zh-hans.react.dev/reference/react/createContext#createcontext.
4.3 useContext()
- 如果 React 没有在父树中找到该特定 context 的任何 provider,useContext() 返回的 context 值将等于你在 创建 context 时指定的 默认值;
- 注意,只有在 上层根本没有匹配的 provider 时才使用
createContext(defaultValue)
调用的默认值。如果存在<SomeContext.Provider value={undefined}>
组件在父树的某个位置,调用 useContext(SomeContext)
的组件 将会 接收到undefined
作为 context 的值。 - 参考官网:
https://zh-hans.react.dev/reference/react/useContext.
5. 附代码
-
context.js
/*** 1. 通常,来自不同文件的组件都会需要读取同一个 context。* 2. 因此,在一个单独的文件内定义 context 便成了常见做法。* 3. 你可以使用 export 语句 将其导出,以便其他文件读取使用*/ import { createContext } from "react";const MessegeContext = createContext();export default MessegeContext;// import { createContext } from 'react';// export const ThemeContext = createContext('light'); // export const AuthContext = createContext(null);
-
Parent.jsx
import React from "react"; import Child from "./Child"; import './index.css' import { useState } from "react"; import MessegeContext from "./context.js";function Parent() {const [notice, setNotice] = useState('孙子,你真棒!!');return(// <div className="parent">// 我是父组件!// <div className="child">// <Child notice={'通知——今天放假!'}/>// </div>// </div>// 这里的属性,只能用 value<MessegeContext.Provider value={notice}><div className="parent">我是父组件!<div className="child"><Child notice={'通知——今天放假!'}/></div></div></MessegeContext.Provider>) }export default Parent;
-
Child.jsx
import React from "react"; import GrandSon from "./GrandSon"; import './index.css'function Child(props){return(<div>我是子组件!!!<br /><br />收到来自于父组件的数据:{props.notice}<br /><br /><div className="grandSon"><GrandSon /></div></div>) }export default Child;
-
GrandSon.jsx
import { useContext } from "react" import MessegeContext from "./context.js";export default function GrandSon(){// 在组件的顶层调用 useContext 来读取和订阅 context。const msgContent = useContext(MessegeContext);console.log(msgContent);return(<div>我是孙组件!!<br />我收到爷爷的信息是:{msgContent}</div>) }
-
componenet–>index.css
.parent{background-color: blueviolet;border: 1px solid;height: 900px;width: 600px;text-align: center; }.child{background-color: green;height: 300px;margin: 20px; }.grandSon{background-color: grey;height: 150px;margin: 20px; }