React hooks - useContext

useContext

        • 用法
        • 使用
          • 以非侵入的方式使用 Context
          • 使用 useContext 重构 useReducer 案例

用法

实现多层组件的数据传递

  1. 在全局创建 Context 对象
  2. 在父组件中使用 Context.Provider 提供数据
  3. 在子组件中使用 useContext 使用数据
import React, { useContext } from 'react'
// 全局
const MyContext = React.createContext(初始数据)
// 父组件
const Father = () => {return <MyContext.Provider value={{name: 'escook', age: 22}}></MyContext.Provider>
}
// 子组件
const Son = () => {const myCtx = useContext(MyContext)return <div><p>姓名:{myCtx.name}</p><p>年龄:{MyCtx.age}</p></div>
} 
使用
// 声明 TS 类型
type ContextType = { count: number; setCount: React.Dispatch<React.SetStateAction<number>> } 
// 1. 创建 Context 对象
const AppContext = React.createContext<ContextType>({} as ContextType) 
export const LevelA: React.FC = () => {// 定义状态const [count, setCount] = useState(0)return (<div style={{ padding: 30, backgroundColor: 'lightblue', width: '50vw' }}><p>count值是:{count}</p><button onClick={() => setCount((prev) => prev + 1)}>+1</button>{/* 2. 使用 Context.Provider 向下传递数据 */}<AppContext.Provider value={{ count, setCount }}> {/* 使用子组件 */}<LevelB /></AppContext.Provider> </div>)
} 
export const LevelB: React.FC = () => {return (<div style={{ padding: 30, backgroundColor: 'lightgreen' }}>{/* 使用子组件 */}<LevelC /></div>)
} 
export const LevelC: React.FC = () => {// 3. 使用 useContext 接收数据const ctx = useContext(AppContext) return (<div style={{ padding: 30, backgroundColor: 'lightsalmon' }}>{/* 4. 使用 ctx 中的数据和方法 */}<p>count值是:{ctx.count}</p> <button onClick={() => ctx.setCount((prev) => prev + 1)}>+1</button><button onClick={() => ctx.setCount(0)}>重置</button> </div>)
}
以非侵入的方式使用 Context

保证父组件中代码的单一性和Provider的通用性,解决父组件中侵入了 <AppContext.Provider> 的问题,
Context.Provider 封装到独立的 Wrapper 函数式组件中。

核心思路:每个 Context 都创建一个对应的 Wrapper 组件,在 Wrapper 组件中使用 Provider 向 children 注入数据。

// 声明 TS 类型
type ContextType = { count: number; setCount: React.Dispatch<React.SetStateAction<number>> }
// 创建 Context 对象
const AppContext = React.createContext<ContextType>({} as ContextType)
// 定义独立的 Wrapper 组件,被 Wrapper 嵌套的子组件会被 Provider 注入数据
export const AppContextWrapper: React.FC<React.PropsWithChildren> = (props) => {// 1. 定义要共享的数据const [count, setCount] = useState(0)// 2. 使用 AppContext.Provider 向下共享数据return <AppContext.Provider value={{ count, setCount }}>{props.children}</AppContext.Provider>
} 
import React from 'react'
import { AppContextWrapper, LevelA } from '@/components/use_context/01.base.tsx'const App: React.FC = () => {return (<AppContextWrapper><!-- AppContextWrapper 中嵌套使用了 LevelA 组件,形成了父子关系 --><!-- LevelA 组件会被当做 children 渲染到 Wrapper 预留的插槽中 --><LevelA /></AppContextWrapper>)
}
export default App 

组件树的嵌套关系为:App => Wrapper => LevelA => LevelB => LevelC。因此在 LevelA、LevelB 和 LevelC 组件中,都可以使用 context 中的数据。

export const LevelA: React.FC = () => {// 使用 useContext 接收数据const ctx = useContext(AppContext)return (<div style={{ padding: 30, backgroundColor: 'lightblue', width: '50vw' }}>{/* 使用 ctx 中的数据和方法 */}<p>count值是:{ctx.count}</p><button onClick={() => ctx.setCount((prev) => prev + 1)}>+1</button><LevelB /></div>)
}
export const LevelC: React.FC = () => {// 使用 useContext 接收数据const ctx = useContext(AppContext)return (<div style={{ padding: 30, backgroundColor: 'lightsalmon' }}>{/* 使用 ctx 中的数据和方法 */}<p>count值是:{ctx.count}</p><button onClick={() => ctx.setCount((prev) => prev + 1)}>+1</button><button onClick={() => ctx.setCount(0)}>重置</button></div>)
}
使用 useContext 重构 useReducer 案例
// 1. 定义 Context 的 TS 类型
// 在这一步,我们必须先明确要向子组件注入的数据都有哪些
type UserInfoContextType = { user: UserType; dispatch: React.Dispatch<ActionType> } 
// 2. 创建 Context 对象
const UserInfoContext = React.createContext<UserInfoContextType>({} as UserInfoContextType) 
// 3. 创建 ContextWrapper 组件
export const UserInfoContextWrapper: React.FC<React.PropsWithChildren> = ({ children }) => {const [state, dispatch] = useImmerReducer(reducer, defaultState, initAction)return <UserInfoContext.Provider value={{ user: state, dispatch }}>{children}</UserInfoContext.Provider>
} 
import React from 'react'
import { UserInfoContextWrapper, Father } from '@/components/use_reducer/01.base.tsx'const App: React.FC = () => {return (<UserInfoContextWrapper><Father /></UserInfoContextWrapper>)
}export default App 
export const Father: React.FC = () => {// 4. 调用 useContext 导入需要的数据const { user: state, dispatch } = useContext(UserInfoContext)const changeUserName = () => dispatch({ type: 'UPDATE_NAME', payload: '刘龙彬' })return (<div><button onClick={changeUserName}>修改用户名</button><p>{JSON.stringify(state)}</p><div className="father">{/* 5. 这里没有必要再往子组件传递 props 了 */}{/* <Son1 {...state} dispatch={dispatch} /><Son2 {...state} dispatch={dispatch} /> */}<Son1 /><Son2 /></div></div>)
} 
const Son1: React.FC = () => {// 6. 把 props 替换为 useContext() 的调用const { dispatch, user } = useContext(UserInfoContext)const add = () => dispatch({ type: 'INCREMENT', payload: 1 })return (<div className="son1"><p>{JSON.stringify(user)}</p><button onClick={add}>年龄+1</button></div>)
} 
const Son2: React.FC = () => {// 7. 把 props 替换为 useContext() 的调用const { dispatch, user } = useContext(UserInfoContext)const sub = () => dispatch({ type: 'DECREMENT', payload: 5 })return (<div className="son2"><p>{JSON.stringify(user)}</p><button onClick={sub}>年龄-5</button><hr /><GrandSon /></div>)
} 
const GrandSon: React.FC = () => {// 8. 把 props 替换为 useContext() 的调用const { dispatch } = useContext(UserInfoContext)const reset = () => dispatch({ type: 'RESET' })return (<><h3>这是 GrandSon 组件</h3><button onClick={reset}>重置</button></>)
} 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/17570.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

全网爆火Remini 粘土滤镜风格,我用ComfyUI一键生成了(保姆级教程)!

一、火爆全网的Remini&#xff01; Remini真的火爆了&#xff01;最近大家的朋友应该都被粘土滤镜刷屏了。 小红书上粘土滤镜、粘土特效的帖子动不动就是几百万浏览量&#xff0c;几千赞。 在有些电商平台上还有人接单&#xff0c;帮忙定制remini粘土风格的照片&#xff01; …

解释浏览器缓存和本地存储的区别,以及如何实现事件的防抖和节流

1:浏览器缓存和本地存储的区别: 浏览器缓存:浏览器缓存是一种临时性的数据存储,用于提高网页加载速度。缓存的数据存储在内存或磁盘中,当用户再次访问相同的资源时,浏览器会优先从缓存中读取数据,而不是从服务器重新请求。缓存的数据可以在浏览器关闭后自动清除,或者根据 HTT…

vue+three.js实现3d系统的搭建

1.首先node.js是12.22版本的&#xff0c;安装three.js可以参考这篇文章 直接用Threejs入门-安装教程_安装three.js-CSDN博客 直接在终端安装three.js即可 npm install --save three 在相同目录下安装vite构建工具 npm install --save-dev vite 在项目里面看package.json中…

神秘顾客调查:第三方渠道监测如何操作?

第三方渠道监测是指通过专业的第三方机构或服务商&#xff0c;对企业的销售渠道进行系统化的监督和评估。这种监测帮助企业了解各渠道的表现&#xff0c;确保合规性&#xff0c;提升市场竞争力。深圳神秘顾客市场调查限公司&#xff08;SMS&#xff09;总结了第三方渠道监测的操…

【安装笔记-20240528-Linux-在 Vultr 云服务器上安装 OpenWRT】

安装笔记-系列文章目录 安装笔记-20240528-Linux-在 Vultr 云服务器上安装测试 OpenWRT 文章目录 安装笔记-系列文章目录安装笔记-20240528-Linux-在 Vultr 云服务器上安装测试 OpenWRT 前言一、软件介绍名称&#xff1a;OpenWRT主页官方介绍 二、安装步骤测试版本&#xff1a…

多function-calling 调用

多function-calling 调用 接上一篇function-calling调用&#xff0c;本篇实现了一个多function-calling的调用。OpenAI会根据function的描述自己来判断应该调用哪个function。最终调用function的动作是由我们来决定的&#xff0c;当然你也可以不调对应的函数。 两个函数分别是…

案例研究|MeterSphere助力万物云构建高效自动化测试平台

万物云空间科技服务股份有限公司&#xff08;以下简称为“万物云”&#xff09;&#xff0c;前身为万科物业发展股份有限公司&#xff0c;是国内领先的物管龙头上市公司。作为一家科技引领的全域空间服务商&#xff0c;万物云致力于打造产业级共享服务平台&#xff0c;基于空间…

1. lambda初体验

首先声明一个函数式接口&#xff0c;就只接口内只有一个抽象方法 //函数式接口 public interface Factory {Object getObject();}接口实现类 public class SubClass implements Factory {Overridepublic Object getObject() {return new User();}}User类 public class User …

酒店提前线上订房小程序源码系统 PHP+MySQL组合开发 源码开源可二开 带完整的安装代码包以及搭建教程

系统概述 随着移动互联网的普及&#xff0c;越来越多的人习惯通过手机进行酒店预订。传统的线下订房方式逐渐无法满足用户的需求&#xff0c;酒店提前线上订房小程序的出现成为必然趋势。该源码系统的开发旨在为酒店提供一个便捷、高效的线上订房平台&#xff0c;提升用户体验…

基于微信小程序+ JAVA后端实现的【医院挂号预约系统】 设计与实现 (内附设计LW + PPT+ 源码+ 演示视频 下载)

项目名称 项目名称&#xff1a; 《基于微信小程序的医院挂号预约系统设计与实现》 项目技术栈 该项目采用了以下核心技术栈&#xff1a; 后端框架/库&#xff1a; Java, SSM框架数据库&#xff1a; MySQL前端技术&#xff1a; 微信小程序, uni-app 项目展示 全文概括 本…

设置单群聊消息扩展

根据消息 ID &#xff0c;对单聊会话或群聊会话中已经发送的消息设置扩展信息。每次最多可以设置 100 个扩展属性信息&#xff0c;最多可设置 300 个。 通过 Server API 操作消息扩展&#xff0c;默认不会向操作者的客户端同步&#xff0c;会导致扩展信息不一致。如有需要&…

MySQL触发器实战:自动执行的秘密

欢迎来到我的博客&#xff0c;代码的世界里&#xff0c;每一行都是一个故事 &#x1f38f;&#xff1a;你只管努力&#xff0c;剩下的交给时间 &#x1f3e0; &#xff1a;小破站 MySQL触发器实战&#xff1a;自动执行的秘密 前言触发器的定义和作用触发器的定义和作用触发器的…

大模型领域新闻跟踪

杨值麟 月之暗面杨植麟&#xff1a;大模型开发是“承包森林”月之暗面集结最强创投&#xff0c;“清华师姐”是最强“助攻”月之暗面杨植麟&#xff1a;互联网研发是“种树”&#xff0c;大模型研发是“承包森林”月之暗面杨植麟复盘大模型创业这一年&#xff1a;向延绵而未知…

搜维尔科技:穿上Xsens Link动作捕捉套装,进行精准的运动捕捉

穿上Xsens Link动作捕捉套装&#xff0c;进行精准的运动捕捉 搜维尔科技&#xff1a;穿上Xsens Link动作捕捉套装&#xff0c;进行精准的运动捕捉

vue 笔记01

目录 01 vuejs中属性的基本使用 02 v-show指令的使用 03 v-if 指令的使用 04 v-for指令的使用 05 v-model 指令 06 template模板标签 07 v-on事件的绑定指令 08 事件中的event对象 01 vuejs中属性的基本使用 {{ }} 叫做mustache模板语法 双花括号 小胡子语法 双花括号…

安卓手机APP开发__构建通话应用

安卓手机APP开发__构建通话应用 目录 概述 依赖项和权限 注册应用 平台集成 注册通话 添加通话 接听来电 拒接来电 去电 将通话置于保持状态 断开连接 转接音频 前台支持 Surface 支持 概述 使用 Telecom Jetpack 库为用户提供最佳视频和音频体验。借助 Teleco…

GO语言 linux部署

https://blog.csdn.net/wangye135/article/details/136177171 一、简述 1. 可以直接在服务器上运行编译好的二进制文件&#xff0c;不需要在服务器上下载语言环境。 2. 内置运行时环境&#xff1a;可执行文件中内置了运行时环境&#xff0c;包括垃圾回收、调度器等&#xff…

Java深拷贝浅拷贝

在Java中&#xff0c;深拷贝和浅拷贝是两种不同的对象复制方式。 浅拷贝&#xff1a;创建一个新对象&#xff0c;然后将原对象的非静态字段复制到新对象中。如果字段是值类型的&#xff0c;那么对该字段执行逐位复制。如果字段是引用类型的&#xff0c;则复制引用但不复制引用的…

SAP 根据报错消息号快速定位问题

通常用户在业务的操作过程中&#xff0c;经常会遇到报错信息&#xff0c;有些报错是系统控制抛出的信息&#xff0c;但是有些报错的信息是根据不同地点业务场景对填写的数据进行判断校验&#xff0c;然后给出的报错信息&#xff0c;正常情况报错信息一般是有文本&#xff0c;或…

【C语言】文件操作讲解

C语言文件操作讲解 文件文件名文件类型数据在内存中的存储 文件缓冲区文件指针文件的打开与关闭fopenfclosefopen与fclose的使用文件的打开方式 文件的顺序读写fputcfgetcfputsfgetsfprintffscanffwritefread输入流与输出流对比scanf\fscanf\sscanf与printf\fprintf\sprintfssc…