当前位置: 首页 > news >正文

[React 进阶系列] React Context 案例学习:使用 TS 及 HOC 封装 Context

[React 进阶系列] React Context 案例学习:使用 TS 及 HOC 封装 Context

具体 context 的实现在这里:[React 进阶系列] React Context 案例学习:子组件内更新父组件的状态。

根据项目经验是这样的,自从换了 TS 之后,就再也没有二次封装过了使用 TS 真的可以有效解决 typo 和 intellisense 的问题

这里依旧使用一个简单的 todo 案例去完成

使用 TypeScript

结构方面采用下面的结构:

❯ tree src
src
├── App.css
├── App.test.tsx
├── App.tsx
├── context
│   └── todoContext.tsx
├── hoc
├── index.css
├── index.tsx
├── logo.svg
├── models
│   └── todo.type.ts
├── react-app-env.d.ts
├── reportWebVitals.ts
└── setupTests.ts4 directories, 11 files

创建 type

这里的 type 指的是 Todo 的类型,以及 context 类型,这是一个简单案例,结构就不会特别的复杂:

  • todo.type.ts

    export type ITodo = {id: number;title: string;description: string;completed: boolean;
    };
    
  • todoContext.tsx

    import { ITodo } from '../models/todo.type';export type TodoContextType = {todos: ITodo[];addTodo: (todo: ITodo) => void;removeTodo: (id: number) => void;toggleTodo: (id: number) => void;
    };
    

    这种 type 的定义,我基本上说 component 在哪里就会定义在哪里,而不会单独创建一个文件在 model 下面去实现,当然,这种其实也挺看个人偏好的……

创建 context

这里主要就是提供一个 context,以供在其他地方调用 useContext 而使用:

export const TodoContext = createContext<TodoContextType | null>(null);

这里 <> 是接受 context 的类型,我个人偏向会使用一个具体的 type 以及 null。其原因是 JS/TS 默认没有初始化和没有实现的变量都是 undefined,也因此使用 undefined 的指向性不是很明确。

而使用 null 代表这个变量存在,因此更具有指向性

虽然在 JS 实现中一般我都偷懒没设置默认值……

没有报错真的会忘……超小声 bb

创建 Provider

Provider 的实现如下:

const TodoProvider: FC<{ children: ReactNode }> = ({ children }) => {const [todos, settodos] = useState<ITodo[]>([{id: 1,title: 'Todo 1',completed: false,description: 'Todo 1',},{id: 2,title: 'Todo 2',completed: false,description: 'Todo 1',},]);const addTodo = (todo: ITodo) => {const newTodo: ITodo = {id: todos.length + 1,title: todo.title,description: todo.description,completed: false,};settodos([...todos, newTodo]);};const removeTodo = (id: number) => {const newTodos = todos.filter((todo) => todo.id !== id);settodos(newTodos);};const toggleTodo = (id: number) => {const newTodos = todos.map((todo) => {if (todo.id === id) {return { ...todo, completed: !todo.completed };}return todo;});settodos(newTodos);};return (<TodoContext.Providervalue={{todos,addTodo,removeTodo,toggleTodo,}}>{children}</TodoContext.Provider>);
};export default TodoProvider;

其实也没什么复杂的,主要就是一个 FC<ChildPops> 这个用法,这代表当前的函数是一个 Functional Component,它只会接受一个参数,并且它的参数会是一个 ReactNode

添加 helper func

如果想要直接使用 const {} = useContext(TodoContest) 的话,TS 会报错——默认值是 null。所以这个时候可以创建一个 helper func,保证返回的 context 一定有值:

export const useTodoContext = () => {const context = useContext(TodoContext);if (!context) {throw new Error('useTodoContext must be used within a TodoProvider');}return context;
};

这样可以保证调用 useTodoContext 一定能够获取值。两个错误对比如下:

在这里插入图片描述

在这里插入图片描述

不过这个时候页面渲染还是有一点问题,因为没有提供对应的 provider:

在这里插入图片描述

使用 HOC

一般的解决方法有两种:

  1. 直接在 Main 上嵌套一个 Provider

    这个的问题就在于,Main 本身就需要调用 context 中的值,如果在这里嵌套的话就会导致 Main 组件中无法使用 context 中的值

  2. 在上层组件中添加对应的 provider

    这样得到 App 层去修改,可以,但是有的情况并不是一个非常的适用,尤其是多个 Provider 嵌套,而其中又有数据依赖的情况下,将 Provider 一层一层往上推意味着创建多个 component 去实现

使用 HOC 的方法是兼具 1 和 2 的解决方案,具体实现如下:

import { ComponentType } from 'react';
import TodoProvider, { TodoContextType } from '../context/todoContext';const withTodoContext = (WrappedComponent: ComponentType<any>) => () =>(<TodoProvider><WrappedComponent /></TodoProvider>);export default withTodoContext;

这样 Main 层面的调用如下:

import React from 'react';
import { Button } from '@mui/material';
import AddIcon from '@mui/icons-material/Add';
import { useTodoContext } from '../context/todoContext';
import withTodoContext from '../hoc/withTodoContext';const Main = () => {const { todos } = useTodoContext();return (<div className="todo-main"><input type="text" /><Button className="add-btn"><AddIcon /></Button><br /><ul>{todos.map((todo) => (<li key={todo.id}>{todo.title}</li>))}</ul></div>);
};export default withTodoContext(Main);

补充一下,如果 HOC 需要接受参数的话,实现是这样的:

const withExampleContext =(WrappedComponent: ComponentType<any>) => (moreProps: ExampleProps) =>(<ExampleProvider><WrappedComponent {...moreProps} /></ExampleProvider>);export default withExampleContext;

这样导出的方式还是使用 withExampleContext(Component),不过上层可以用 <Component prop1={} prop2={} /> 的方式向 Component 中传值

调用

完整实现如下:

const Main = () => {const [newTodo, setNewTodo] = useState('');const { todos, addTodo, toggleTodo } = useTodoContext();const onChangeInput = (e: React.ChangeEvent<HTMLInputElement>) => {setNewTodo(e.target.value);};const onAddTodo = () => {addTodo({title: newTodo,description: '',completed: false,});setNewTodo('');};const onCompleteTodo = (id: number) => {toggleTodo(id);};return (<div className="todo-main"><input type="text" value={newTodo} onChange={onChangeInput} /><Button className="add-btn" onClick={onAddTodo}><AddIcon /></Button><br /><ul>{todos.map((todo) => (<likey={todo.id}style={{textDecoration: todo.completed ? 'line-through' : 'none',cursor: 'pointer',}}onClick={() => onCompleteTodo(todo.id)}>{todo.title}</li>))}</ul></div>);
};export default withTodoContext(Main);

效果如下:

在这里插入图片描述

TS 提供的自动提示如下:

在这里插入图片描述

相关文章:

[React 进阶系列] React Context 案例学习:使用 TS 及 HOC 封装 Context

[React 进阶系列] React Context 案例学习&#xff1a;使用 TS 及 HOC 封装 Context 具体 context 的实现在这里&#xff1a;[React 进阶系列] React Context 案例学习&#xff1a;子组件内更新父组件的状态。 根据项目经验是这样的&#xff0c;自从换了 TS 之后&#xff0c;…...

网络编程:网络编程基础

一、网络发展 1.TCP/IP两个协议阶段 TCP/IP协议已分成了两个不同的协议&#xff1a; 用来检测网络传输中差错的传输控制协议TCP 专门负责对不同网络进行2互联的互联网协议IP 2.网络体系结构 OSI体系口诀&#xff1a;物链网输会示用 2.1网络体系结构概念 每一层都有自己独…...

力扣热题100_矩阵_73_矩阵置零

文章目录 题目链接解题思路解题代码 题目链接 73.矩阵置零 给定一个 m x n 的矩阵&#xff0c;如果一个元素为 0 &#xff0c;则将其所在行和列的所有元素都设为 0 。请使用 原地 算法。 示例 1&#xff1a; 输入&#xff1a;matrix [[1,1,1],[1,0,1],[1,1,1]] 输出&…...

C++程序设计-第四/五章 函数和类和对象【期末复习|考研复习】

前言 总结整理不易&#xff0c;希望大家点赞收藏。 给大家整理了一下C程序设计中的重点概念&#xff0c;以供大家期末复习和考研复习的时候使用。 C程序设计系列文章传送门&#xff1a; 第一章 面向对象基础 第四/五章 函数和类和对象 第六/七/八章 运算符重载/包含与继承/虚函…...

C#快速入门基础

本篇文章从最基础的C#编程开始学习&#xff0c;经过非常优秀的面向对象编程思想和方法的学习&#xff0c;为C#编程打下基础。 第 01 章 C#开发环境之VS使用和.NET平台基础 1.1 Visual Studio 开发环境 1.1.1 硬件环境 i5CPUi5CPU&#xff08;建议 4核 4线程或以上 &#xff0…...

UnityShader常用算法笔记(颜色叠加混合、RGB-HSV-HSL的转换、重映射、UV序列帧动画采样等,持续更新中)

一.颜色叠加混合 1.Blend混合 // 正常&#xff0c;透明度混合 Normal Blend SrcAlpha OneMinusSrcAlpha //柔和叠加 Soft Additive Blend OneMinusDstColor One //正片叠底 相乘 Multiply Blend DstColor Zero //两倍叠加 相加 2x Multiply Blend DstColor SrcColor //变暗…...

Vue3调用钉钉api,内嵌H5微应用单点登录对接

钉钉内嵌H5微应用单点登录对接 https://open.dingtalk.com/document/isvapp/obtain-the-userid-of-a-user-by-using-the-log-free 前端需要的代码 1、安装 dingtalk-jsapi npm install dingtalk-jsapi2、在所需页面引入 import * as dd from dingtalk-jsapi; // 引入钉钉a…...

UE5 局域网联机,寻找会话失败。

目录 参考资料&#xff1a; 尝试解决办法 1.1在【项目名.Build.cs】脚本中添加该行&#xff0c;添加后关闭编辑器&#xff0c;重新生成解决方案。​编辑 2.检查是否在同一个C类子网 参考资料&#xff1a; 1.Cant find session in LAN - Programming & Scripting / Mul…...

Windows系统安装MongoDB并结合内网穿透实现公网访问本地数据库

文章目录 前言1. 安装数据库2. 内网穿透2.1 安装cpolar内网穿透2.2 创建隧道映射2.3 测试随机公网地址远程连接 3. 配置固定TCP端口地址3.1 保留一个固定的公网TCP端口地址3.2 配置固定公网TCP端口地址3.3 测试固定地址公网远程访问 前言 MongoDB是一个基于分布式文件存储的数…...

Hadoop伪分布式配置--没有DataNode或NameNode

一、原因分析 重复格式化NameNode 二、解决方法 1、输入格式化NameNode命令&#xff0c;找到data和name存放位置 ./bin/hdfs namenode -format 2、删除data或name&#xff08;没有哪个删哪个&#xff09; sudo rm -rf data 3、重新格式化NameNode 4、重新启动即可。...

柚见第十期(后端队伍接口详细设计)

创建队伍 用户可以 创建 一个队伍&#xff0c;设置队伍的人数、队伍名称&#xff08;标题&#xff09;、描述、超时时间 P0 队长、剩余的人数 聊天&#xff1f; 公开 或 private 或加密 信息流中不展示已过期的队伍 请求参数是否为空&#xff1f;是否登录&#xff0c;未登录不…...

【李沐论文精读】GPT、GPT-2和GPT-3论文精读

论文&#xff1a; GPT&#xff1a;Improving Language Understanding by Generative Pre-Training GTP-2&#xff1a;Language Models are Unsupervised Multitask Learners GPT-3&#xff1a;Language Models are Few-Shot Learners 参考&#xff1a;GPT、GPT-2、GPT-3论文精读…...

新版Android Studio火烈鸟 在新建项目工程时 无法选java的语言模板解决方法

前言 最近下载最新版androidstudio时 发现不能勾选java语言模板了 如果快速点击下一步 新建项目 默认是kotlin语言模板 这可能和google主推kt语言有关 勾选1 如图所示 如果勾选 No Activity 这个模板 是可以选java语言模板的 但是里面没有默认的Activity 勾选2 和以前的用法…...

github(不是git啊)操作记录(踩坑)

专栏介绍与文章目录-CSDN博客 github是程序员绕不开的东西。 网站打不开&#xff1f; 向雇主或有关部门申请合法信道连接互联网。 明明账号密码都对却登录失败&#xff1f; 向雇主或有关部门申请合法信道连接互联网。 重置密码失败&#xff1f; 向雇主或有关部门申请合法信道…...

【SpringCloud微服务实战01】Eureka 注册中心

前言 在 Eureka 架构中&#xff0c;微服务角色有两类&#xff1a; EurekaServer &#xff1a;服务端&#xff0c;注册中心 记录服务信息 心跳监控 EurekaClient &#xff1a;客户端 Provider &#xff1a;服务提供者&#xff0c;例如案例中的 user-service …...

Python之函数进阶-柯里化

Python之函数进阶-柯里化 柯里化是一种将多参数函数转化为单参数高阶函数的技术。 具体来说&#xff0c;柯里化过程会将一个接受多个参数的函数&#xff0c;转换成一系列接受一个参数的函数&#xff0c;这些函数在内部组合起来&#xff0c;最终完成原函数的运算。 柯里化是一…...

Spring Cloud项目整合Sentinel及简单使用

说明&#xff1a;Sentinel是阿里巴巴开发的微服务治理中间件&#xff0c;可用于微服之间请求的流量管控、权限控制、熔断降级等场景。本文介绍如何在Spring Cloud项目中整合Sentinel&#xff0c;以及Sentinel的简单使用。 环境 首先搭建一个简单的微服务环境&#xff0c;有以…...

【话题】人工智能迷惑行为大赏

随着ChatGPT热度的攀升&#xff0c;越来越多的公司也相继推出了自己的AI大模型&#xff0c;如文心一言、通义千问等。各大应用也开始内置AI玩法&#xff0c;如抖音的AI特效&#xff5e;在使用过程中往往会遇到一些问题&#xff0c;让你不得不怀疑&#xff0c;这真的是人工智能吗…...

Jsp在Javaweb中扮演什么角色?

1.什么是Jsp JSP&#xff08;Java Server Pages&#xff0c;Java 服务器页面&#xff09;是一种动态网页技术&#xff0c;它允许在 HTML 页面中嵌入 Java 代码&#xff0c;并由 Web 服务器在请求页面时动态生成 HTML 页面。JSP 通常用于创建动态 Web 内容&#xff0c;如交互式表…...

部署docker仓库harbor

1、下载包 1、包已上传有两个harbor.v2.6.0.tar与harbor.tar 2、harbor.tar解压后会生成harbor目录&#xff0c;将harbor.v2.6.0.tar移动到harbor目录下。 3、执行harbor目录下的install.sh 4、执行完后修改配置文件 2、修改配置文件 vim /root/harbor/make/ harbor.yml.tmpl …...

西安家谱印刷厂哪家好

你知道吗&#xff1f;我走访了全国20多个宗亲会&#xff0c;发现一个扎心的事实——超过70%的家庭在第一次修谱时&#xff0c;都踩过同样的坑。有位陕西的陈姓宗长&#xff0c;花了整整3年时间收集家族资料&#xff0c;结果找了一家小印刷厂&#xff0c;拿到手的家谱&#xff0…...

2026年AI模型接口中转站真实测评:五大主流大模型API聚合平台深度实测调研指南

进入2026年&#xff0c;大语言模型的工程化落地已经走完从尝鲜到规模化普及的全流程&#xff0c;对于广大AI应用开发者而言&#xff0c;AI大模型接口中转站早就不是过去仅承担接口转发的简单工具&#xff0c;如今它已经承担起链路高可用保障、多模型负载均衡、跨协议自动转换等…...

掌握AI技能配置技巧 大幅提升日常办公开发效率

P.S. 目前国内还是很缺AI人才的&#xff0c;希望更多人能真正加入到AI行业&#xff0c;共同促进行业进步&#xff0c;增强我国的AI竞争力。想要系统学习AI知识的朋友可以看看我精心打磨的教程 http://blog.csdn.net/jiangjunshow&#xff0c;教程通俗易懂&#xff0c;高中生都能…...

深度学习篇---torch 和 torchvision

torch 和 torchvision 是 PyTorch 生态中最核心的两个库。简单来说&#xff0c;torch 是基础框架&#xff0c;负责张量计算和自动微分&#xff1b;而 torchvision 是专注于视觉任务的工具集&#xff0c;让你能方便地加载数据、使用预训练模型和进行图像处理。&#x1f525; tor…...

通过curl命令快速测试Taotoken的API连通性与返回

&#x1f680; 告别海外账号与网络限制&#xff01;稳定直连全球优质大模型&#xff0c;限时半价接入中。 &#x1f449; 点击领取海量免费额度 通过curl命令快速测试Taotoken的API连通性与返回 在集成大模型服务时&#xff0c;直接使用curl命令进行API测试是一种高效且通用的…...

MySQL 全文索引实战:搜索功能的正确打开方式

开场白 做搜索功能的时候&#xff0c;很多人第一反应是 LIKE ‘%关键词%’&#xff0c;数据量小的时候没问题&#xff0c;数据一大直接全表扫描。我之前有个项目&#xff0c;商品表的 LIKE 搜索在 50 万条数据时就要 3 秒以上&#xff0c;根本没法用。后来上了全文索引&#x…...

3步掌握Android虚拟定位:FakeLocation完全使用指南

3步掌握Android虚拟定位&#xff1a;FakeLocation完全使用指南 【免费下载链接】FakeLocation Xposed module to mock locations per app. 项目地址: https://gitcode.com/gh_mirrors/fak/FakeLocation FakeLocation是一款基于Xposed框架的Android虚拟定位工具&#xff…...

这次终于选对了!2026年超实用AI论文平台榜单,免费高效产出合规稿

2026 年实测 10 款主流 AI 论文工具&#xff0c;千笔AI以全流程覆盖 语义级降重 免费查重领跑综合榜&#xff1b;ThouPen 稳坐留学生毕业全流程工具头把交椅&#xff1b;免费工具中DeepSeek Scholar、豆包学术版表现亮眼&#xff0c;30 分钟即可生成万字高质量初稿&#xff0…...

使用Taotoken后API调用延迟与账单透明度的实际体验

&#x1f680; 告别海外账号与网络限制&#xff01;稳定直连全球优质大模型&#xff0c;限时半价接入中。 &#x1f449; 点击领取海量免费额度 使用Taotoken后API调用延迟与账单透明度的实际体验 1. 引言 对于需要调用多种大模型API的开发者而言&#xff0c;统一接入和成本管…...

ChatGPT新闻稿写作终极模板包(含敏感词实时拦截表+信源可信度打分卡+记者视角反问清单):仅开放前500份

更多请点击&#xff1a; https://kaifayun.com 第一章&#xff1a;ChatGPT新闻稿写作终极模板包概览 本模板包专为公关、市场与内容团队设计&#xff0c;整合了新闻稿结构化框架、语义优化提示词库、合规性检查清单及多平台适配输出模块&#xff0c;支持从初稿生成到终稿发布…...