React自定义Hook之useMutilpleRef
概要
我们在React开发时候,有时候需要绑定列表中的多个元素,便于后面对列表中单个元素的操作,但是常用的hook函数useRef只能绑定一个DOM元素,本文提供一个可以解决该问题的自定义hook方法,useMutilpleRef。
代码及实现
基本功能
本例使用Map来缓存DOM元素的引用,如果DOM元素存在,则缓存在Map中;如果DOM元素被删除,则在Map中对应的键值对也就被删除。
代码实现
export const useMutipleRefs = <T extends HTMLElement>() => {const refs = useRef<Map<string|number, T> |null>(new Map<string|number, T>());const setRef = (key:string) => (el:T | null) => {if (el) {refs.current!.set(key, el);}else {refs.current!.delete(key);}} useEffect(()=>{return ()=> {refs.current = null};}, []);return {refs, setRef};
}
- 该方法不用接受任何参数,采用泛型约束,只处理DOM元素;
- 采用Map来缓存DOM元素,key值可以是字符串,以支持React 18的useId hook函数,也可以是普通数字;
- 该方法的返回值包括两部分,首先是绑定了DOM元素引用的Map,该Map的内容可以被迭代查询,以支持各种复杂的应用场景;
- 返回值的另一部分是setRef 方法,该方法在绑定元素的时候被调用,参数可以接受HTMLElement和空值,空值用于删除的情况;
- 在组件被卸载时候,释放资源。
使用实例
下面是一个人员列表的例子,可以通过性别过滤列表中的元素,每个元素需要支持删除操作。
关键代码如下, 完整代码请见附录:
响应式数据定义如下:
const [gender, setGender] = useState<Gender>(Gender.Female);
const [filteredIds, setFilteredIds] = useState<Array<number|string>>([]);
const userUI = useMemo(()=> users.filter(u=> u.gender === gender && !filteredIds.includes(u.id)), [gender, filteredIds]);
监听内容如下:
- 对当前选中的性别进行监听;
- 对要删除的User进行监听;
- 对列表内容进行缓存,只有选中的性别和要删除的Id数组发生变化,它才变化。
主要的点击事件代码如下:
type funcType = (event:MouseEvent)=>void;
const handleClickGender = (gender:Gender):funcType=>(event:MouseEvent)=> {setGender(gender);
}
const clickDelete = (index:number|string)=> {console.log(index);setFilteredIds(prev=>[...prev, index]);
}
- 性别过滤按钮点击时候,触发handleClickGender
- 删除按钮点击时候,触发clickDelete
Refs 相关的代码
const {refs, setRef} = useMutipleRefs();
useEffect(()=> {console.log(refs.current);
}, [userUI])<tbody>{userUI.map((user, index)=>(<tr key={user.id} ref={setRef(user.id)}><td>{index + 1}</td><td>{user.name}</td><td>{user.gender === Gender.Female ? "Female": "Male"}</td><td>{user.married? "Yes": "No"}</td><td><button className="btn btn-success" onClick={()=>clickDelete(user.id)}>Delete</button></td></tr>))}
</tbody>
- 调用useMutipleRefs过的初始的refs的Map对象和setRef方法
- 对表格中的每个tr,调用setRef,传入用户Id
代码运行
程序默认是获取所有Female的User信息,因此初始时候,有三个User的引用
点击Male按钮,显示有两个Male的User
Map中的数据更新为所有Male的Tr引用。
点击删除第一个Delete按钮
数据成功删除
Map中缓存的DOM引用,也同时被删除
使用中额外注意的问题
本文提供的缓存方法,监听的DOM对象的类型是HTMLElement,它是DOM元素的基类,如果要使用其它DOM的特有属性,请在调用时候,明确具体类型。
例如存的DOM元素是input,并且需要在后面使用input的value,在调用该方法是,请明确Input的的类型,useMutipleRefs(),否则无获取不到其value值。
结论
本文提供的自动Hook useMutipleRefs可以实现对列表中多个元素引用值的缓存,在DOM元素在创建时候,可以同步创建,删除时候可以同步删除。
附录
完整代码
"use client"
import { FC, useEffect, useMemo, useState } from "react";
import { ReactElement, MouseEvent,useId } from "react";
import { usePrevious, useMutipleRefs } from "../hooks";
import "@/app/assets/bootstrap.min.css"
interface IProps{}enum Gender {Male=0,Female
}interface IUser {id:number|string;name:string;gender:Gender;married:boolean;
}const Team:FC<IProps> = ({}):ReactElement => {const users = [{id:useId(),name:"abc",gender:Gender.Female,married:false},{id:useId(),name:"def",gender:Gender.Male,married:false},{id:useId(),name:"ghi",gender:Gender.Female,married:true},{id:useId(),name:"jkl",gender:Gender.Male,married:false},{id:useId(),name:"mno",gender:Gender.Female,married:true}] as Array<IUser>;const [gender, setGender] = useState<Gender>(Gender.Female);type funcType = (event:MouseEvent)=>void;
const handleClickGender = (gender:Gender):funcType=>(event:MouseEvent)=> {setGender(gender);
} const [filteredIds, setFilteredIds] = useState<Array<number|string>>([]);
const userUI = useMemo(()=> users.filter(u=> u.gender === gender && !filteredIds.includes(u.id)), [gender, filteredIds]);const {refs, setRef} = useMutipleRefs();const clickDelete = (index:number|string)=> {console.log(index);setFilteredIds(prev=>[...prev, index]);}useEffect(()=> {console.log(refs.current); }, [userUI])return <><div className="btn-group" role="group" aria-label="Basic outlined example"><button className="btn btn-primary" onClick={handleClickGender(Gender.Female)}>Female</button><button className="btn btn-warning" onClick={handleClickGender(Gender.Male)}>Male</button></div><table className="table table-striped" style={{width:"50%"}}><thead><tr><th>Id</th><th>Name</th><th>Gender</th><th>Married</th><th>Operation</th></tr> </thead><tbody>{userUI.map((user, index)=>(<tr key={user.id} ref={setRef(user.id)}><td>{index + 1}</td><td>{user.name}</td><td>{user.gender === Gender.Female ? "Female": "Male"}</td><td>{user.married? "Yes": "No"}</td><td><button className="btn btn-success" onClick={()=>clickDelete(user.id)}>Delete</button></td></tr>))}</tbody></table></>
}export default Team;
相关文章:

React自定义Hook之useMutilpleRef
概要 我们在React开发时候,有时候需要绑定列表中的多个元素,便于后面对列表中单个元素的操作,但是常用的hook函数useRef只能绑定一个DOM元素,本文提供一个可以解决该问题的自定义hook方法,useMutilpleRef。 代码及实…...
蛋白质大语言模型ESM介绍
ESM(Evolutionary Scale Modeling)是 Meta AI Research 团队开发的一系列用于蛋白质的预训练语言模型。这些模型在蛋白质结构预测、功能预测和蛋白质设计等领域展现出了强大的能力。以下是对 ESM 的详细介绍: 核心特点 大规模预训练:基于大规模蛋白质序列数据进行无监督学…...

从线性到非线性:简单聊聊神经网络的常见三大激活函数
大家好,我是沛哥儿,我们今天一起来学习下神经网络的三个常用的激活函数。 引言:什么是激活函数 激活函数是神经网络中非常重要的组成部分,它引入了非线性因素,使得神经网络能够学习和表示复杂的函数关系。 在神经网络…...
【算法笔记】贪心算法
一、什么是贪心算法? 贪心算法是一种在每一步选择中都采取当前看起来最优(最“贪心”)的策略,从而希望得到全局最优解的算法设计思想。 核心思想:每一步都做出局部最优选择,不回退。适用场景:…...
Node.js 开发项目
初始化 npm init## npm install 编辑packege.json 添加,以支持ES6的语法 "type": "module" 连接mysql示例 import db from ./db/ops_mysql.jsconst createTable async () > {const insert_data CREATE TABLE IF NOT EXISTS users (…...

网络准入控制系统推荐:2025年构建企业网络安全的第一道防线
随着信息技术的飞速发展,企业网络环境日益复杂,阳途网络准入控制系统作为一种先进的网络安全解决方案,其核心是确保网络接入的安全性。 一、网络准入控制系统的基本原理与功能 网络准入控制以“只有合法的用户、安全的终端才可以接入网络”为…...

XSS跨站--订单和Shell箱子后门
本文主要内容 手法 XSS平台使用 XSS工具使用 XSS结合其他漏洞 XSS具体使用场景 某订单系统XSS盲打_平台 某Shell箱子系统XSS盲打_工具 [1]订单系统经典案例 第一个简易攻击流程(订单系统):通过平台完成XSS跨站之后&a…...

游戏遭遇DDoS攻击如何快速止损?实战防御策略与应急响应指南
是不是很抽象 我自己画的 一、游戏DDoS攻击特征深度解析 游戏行业DDoS攻击呈现复合型特征,2023年监测数据显示,针对游戏服务器的攻击中,63%采用UDP反射放大HTTP慢速攻击组合,攻击峰值达3.2Tbps。攻击者利用游戏协议特性ÿ…...

cocos creator使用jenkins打包流程,打包webmobile
windows电脑使用 如果你的电脑作为打包机,一定要锁定自己的ip,如果ip动态获取,可能后续会导致jenkins无法访问,还需要重新配置jenkins和http-server的端口 从jenkins官网下载windows版 Thank you for downloading Windows Stable installer 1.jenkins安…...

自动驾驶(ADAS)领域常用数据集介绍
1. KITTI 数据集 简介:由德国卡尔斯鲁厄理工学院与丰田研究院联合创建,是自动驾驶领域最经典的评测基准,涵盖立体视觉、光流、3D检测等任务。包含市区、乡村和高速公路场景的真实数据,标注对象包括车辆、行人等,支持多…...
C++ 部署的性能优化方法
一、使用结构体提前存放常用变量 在编写前后处理函数时,通常会多次用到一些变量,比如模型输入 tensor 的 shape,count 等等,若在每个处理函数中都重复计算一次,会增加部署时的计算量。对于这种情况,可以考…...

关于IDEA的循环依赖问题
bug描述:(java: 模块循环不支持注解处理。请确保将循环 [...] 中的所有模块排除在注解处理之外) 解决方法:...

如何在idea中写spark程序
在 IntelliJ IDEA 中编写 Spark 程序,可按以下步骤进行: 1. 创建新项目 打开 IntelliJ IDEA,选择File -> New -> Project。在左侧面板选择Maven或者Gradle(这里以 Maven 为例),确保Project SDK选择…...

RAG工程-基于LangChain 实现 Advanced RAG(预检索优化)
Advanced RAG 概述 Advanced RAG 被誉为 RAG 的第二范式,它是在 Naive RAG 基础上发展起来的检索增强生成架构,旨在解决 Naive RAG 存在的一些问题,如召回率低、组装 prompt 时的冗余和重复以及灵活性不足等。它重点聚焦在检索增强࿰…...
关于常量指针和指向常量的指针
关于指针,对于常量指针和指向常量的指针也是傻傻分不清。看到定义时,不知道是指针不能变,还是指针指向的内容不能变量。 先看形式: const char * A; char * const B; 这两种有什么区别?傻傻分不清。 A这种定义&am…...

《Masked Autoencoders Are Scalable Vision Learners》---CV版的BERT
目录 一、与之前阅读文章的关系? 二、标题:带掩码的自auto编码器是一个可拓展的视觉学习器 三、摘要 四、核心图 五、结果图 六、不同mask比例对比图 七、“Introduction” (He 等, 2021, p. 1) 引言 八、“Related Work” (He 等, 2021, p. 3)相…...

高压直流输电MATLAB/simulink仿真模型+说明文档
1.模型简介 本仿真模型基于MATLAB/Simulink(版本MATLAB 2018Ra)软件。建议采用matlab2018 Ra及以上版本打开。(若需要其他版本可联系代为转换) 使用一个传输功率为1000MW(500 kV,2 kA)直流互连…...

locust压力测试
安装 pip install locust验证是否安装成功 locust -V使用 网上的教程基本上是前几年的,locust已经更新了好几个版本,有点过时了,在此做一个总结 启动 默认是使用浏览器进行设置的 # 使用浏览器 locust -f .\main.py其他参数 Usage: locust […...
python 线程池顺序执行
在Python中,线程池(ThreadPoolExecutor)默认是并发执行任务的,但若需要实现任务的顺序执行(按提交顺序执行或按结果顺序处理),可以通过以下方案实现: 方案一:强制单线程&…...

第十二届蓝桥杯 2021 C/C++组 空间
目录 题目: 题目描述: 题目链接: 思路: 思路详解: 代码: 代码详解: 题目: 题目描述: 题目链接: 空间 - 蓝桥云课 思路: 思路详解&#…...

以太网的mac帧格式
一.以太网的mac帧 帧的要求 1.长度 2.物理层...
前端如何使用Mock模拟数据实现前后端并行开发,提升项目整体效率
1. 安装 Mock.js npm install mockjs --save-dev # 或使用 CDN <script src"https://cdn.bootcdn.net/ajax/libs/Mock.js/1.0.0/mock-min.js"></script>2. 创建 Mock 数据文件 在项目中新建 mock 目录,创建 mock.js 文件: // m…...
【hadoop】HBase shell 操作
1.创建course表 hbase(main):002:0> create course,cf 2.查看HBase所有表 hbase(main):003:0> list 3.查看course表结构 hbase(main):004:0> describe course 4.向course表插入数据 hbase(main):005:0> put course,001,cf:cname,hbase hbase(main):006:0> …...
如何使用 Redis 缓存验证码
目录 🧠 Redis 缓存验证码的工作原理 🧰 实现流程 1. 安装 Redis 和 Python 客户端 2. 生成并缓存验证码 示例代码:生成并存储验证码 3. 发送验证码(以短信为例) 4. 校验验证码 示例代码:校验验证码…...
深度学习---框架流程
核心六步 一、数据准备 二、模型构建 三、模型训练 四、模型验证 五、模型优化 六、模型推理 一、数据准备:深度学习的基石 数据是模型的“燃料”,其质量直接决定模型上限。核心步骤包括: 1. 数据收集与标注 来源:公开数据集…...

业绩回暖、股价承压,三只松鼠赴港上市能否重构价值锚点?
在营收重返百亿俱乐部后,三只松鼠再度向资本市场发起冲击。 4月25日,这家坚果零食巨头正式向港交所递交上市申请书,若成功登陆港股,将成为国内首个实现“AH”双上市的零食品牌。 其赴港背后的支撑力,显然来自近期披露…...

JAVA-StringBuilder使用方法
JAVA-StringBuilder使用方法 常用方法 append(Object obj) 追加内容到末尾 sb.append(" World"); insert(int offset, Object obj) 在指定位置插入内容 sb.insert(5, “Java”); delete(int start, int end) 删除指定范围的字符 sb.delete(0, 5); replace(int start…...

【Python】Matplotlib:立体永生花绘制
本文代码部分实现参考自CSDN博客:https://blog.csdn.net/ak_bingbing/article/details/135852038 一、引言 Matplotlib作为Python生态中最著名的可视化库,其三维绘图功能可以创造出令人惊叹的数学艺术。本文将通过一个独特的参数方程,结合极…...

Unity AI-使用Ollama本地大语言模型运行框架运行本地Deepseek等模型实现聊天对话(一)
一、Ollama介绍 官方网页:Ollama官方网址 中文文档参考:Ollama中文文档 相关教程:Ollama教程 Ollama 是一个开源的工具,旨在简化大型语言模型(LLM)在本地计算机上的运行和管理。它允许用户无需复杂的配置…...
terraform使用vault动态管多理云账号AK/SK
为了使用 Terraform 和 HashiCorp Vault 动态管理多个云账号的 Access Key (AK) 和 Secret Key (SK),可以按照以下步骤实现安全、自动化的凭证管理: 一、架构概述 核心组件: Vault:存储或动态生成云账号的 AK/SK,提供…...