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

react中hooks之useRef 用法总结

1. 基本概念

useRef 是 React 的一个 Hook,返回一个可变的 ref 对象,其 .current 属性被初始化为传入的参数。这个对象在组件的整个生命周期内保持不变。

2. 主要用途和特性

2.1 获取 DOM 元素实例

function TextInputWithFocusButton() {const inputEl = useRef(null);const onButtonClick = () => {// 直接访问 DOM 元素inputEl.current.focus();};return (<><input ref={inputEl} type="text" /><button onClick={onButtonClick}>聚焦输入框</button></>);
}

2.2 存储组件渲染周期之间的共享数据

  • useRef 只会在组件初始化时执行一次
  • state 改变引起的重新渲染不会导致 useRef 重新执行
  • 适合存储不需要触发视图更新的数据
function Counter() {const [count, setCount] = useState(0);const renderCount = useRef(0);  // 用于记录渲染次数useEffect(() => {renderCount.current += 1;console.log(`组件已渲染 ${renderCount.current} 次`);});return (<div><p>当前计数: {count}</p><button onClick={() => setCount(count + 1)}>增加</button></div>);
}

2.3 useRef 的重要特性

  1. current 值的修改不会触发重新渲染
function Example() {const countRef = useRef(0);const handleClick = () => {// 修改 ref 不会导致组件重新渲染countRef.current += 1;console.log('当前值:', countRef.current);};return <button onClick={handleClick}>点击</button>;
}
  1. 不应作为其他 Hooks 的依赖项
function BadExample() {const valueRef = useRef(0);// ❌ 错误示例useEffect(() => {console.log(valueRef.current);}, [valueRef.current]); // 不要这样做
}function GoodExample() {const valueRef = useRef(0);// ✅ 正确示例useEffect(() => {console.log(valueRef.current);}); // 不将 ref 作为依赖项
}

3. forwardRef 和 useImperativeHandle

3.1 基本用法示例

// CustomInput.jsx
import React, { forwardRef, useImperativeHandle, useRef } from 'react';const CustomInput = forwardRef((props, ref) => {const inputRef = useRef();useImperativeHandle(ref, () => ({// 只暴露需要的方法focus: () => {inputRef.current.focus();},getValue: () => {return inputRef.current.value;}}));return <input ref={inputRef} {...props} />;
});// Parent.jsx
function Parent() {const inputRef = useRef();const handleClick = () => {inputRef.current.focus();console.log(inputRef.current.getValue());};return (<div><CustomInput ref={inputRef} /><button onClick={handleClick}>操作输入框</button></div>);
}

3.2 复杂组件示例(不同粒度的暴露)

const ComplexComponent = forwardRef((props, ref) => {const inputRef = useRef();const checkboxRef = useRef();const formRef = useRef();useImperativeHandle(ref, () => ({// 粒度级别 1:表单级操作form: {reset: () => {inputRef.current.value = '';checkboxRef.current.checked = false;},validate: () => {return inputRef.current.value.length > 0;}},// 粒度级别 2:具体输入框操作input: {focus: () => inputRef.current.focus(),getValue: () => inputRef.current.value,setValue: (value) => {inputRef.current.value = value;}},// 粒度级别 3:简单方法clear: () => {inputRef.current.value = '';}}));return (<form ref={formRef}><input ref={inputRef} type="text" /><input ref={checkboxRef} type="checkbox" /></form>);
});// 使用示例
function ComplexParent() {const componentRef = useRef();const handleOperations = () => {// 使用不同粒度的操作componentRef.current.form.reset();componentRef.current.input.focus();componentRef.current.input.setValue('新值');componentRef.current.clear();if (componentRef.current.form.validate()) {console.log('表单验证通过');}};return (<div><ComplexComponent ref={componentRef} /><button onClick={handleOperations}>执行操作</button></div>);
}

4. 注意事项

  1. useRef 不能直接引用函数式组件,必须配合 forwardRef 使用
  2. useRef 的值改变不会触发重新渲染,如果需要在值改变时重新渲染,应使用 useState
  3. 使用 useImperativeHandle 时,应该只暴露必要的方法,保持良好的封装性
  4. 避免在 render 过程中读取或写入 ref.current

5. 最佳实践

  1. 使用 TypeScript 定义暴露的接口类型
  2. 合理划分暴露方法的粒度
  3. 文档化暴露的方法
  4. 遵循最小暴露原则
  5. 在清理阶段(cleanup)正确处理 ref,特别是涉及定时器等资源时

6. 使用场景建议

  1. 访问 DOM 元素或组件实例
  2. 存储定时器 ID
  3. 存储上一次的值
  4. 存储不需要触发重新渲染的数据
  5. 跨组件方法调用(通过 forwardRef)

通过合理使用 useRef,可以优化组件性能,实现更复杂的组件交互,同时保持代码的可维护性和可读性。

相关文章:

react中hooks之useRef 用法总结

1. 基本概念 useRef 是 React 的一个 Hook&#xff0c;返回一个可变的 ref 对象&#xff0c;其 .current 属性被初始化为传入的参数。这个对象在组件的整个生命周期内保持不变。 2. 主要用途和特性 2.1 获取 DOM 元素实例 function TextInputWithFocusButton() {const inpu…...

使用 Docker 部署 Java 项目(通俗易懂)

目录 1、下载与配置 Docker 1.1 docker下载&#xff08;这里使用的是Ubuntu&#xff0c;Centos命令可能有不同&#xff09; 1.2 配置 Docker 代理对象 2、打包当前 Java 项目 3、进行编写 DockerFile&#xff0c;并将对应文件传输到 Linux 中 3.1 编写 dockerfile 文件 …...

如何在Ubuntu上安装和配置Git

版本控制系统&#xff08;VCS&#xff09;是软件开发过程中不可或缺的工具之一&#xff0c;它帮助开发者跟踪代码变更、协作开发以及管理不同版本的项目。Git作为当前最流行的分布式版本控制系统&#xff0c;因其高效性和灵活性而广受青睐。本文将指导你如何在Ubuntu操作系统上…...

FPGA 21 ,深入理解 Verilog 中的基数,以及二进制数与十进制数之间的关系( Verilog中的基数 )

目录 前言 一. 基数基础 1.1 基数介绍 2.1 基数符号 3.1 二进制数 二. 二进制与十进制数 三. 二进制数 3.1 定义寄存器类型变量 3.2 定义线网类型变量 3.3 赋值操作 3.4 解析二进制数为十进制数 四. 代码示例 五. 注意事项 六. 更多操作 前言 在Verilog中&#…...

【redis】redis-cli命令行工具的使用

redis-cli命令行工具是一个功能强大的Redis客户端&#xff0c;它允许用户与Redis数据库进行交互和管理。 以下是一些常用参数的使用说明&#xff1a; 基本连接参数 -h, --host <hostname>&#xff1a;指定要连接的Redis服务器的主机名或IP地址。如果未指定&#xff0c;…...

使用Matplotlib显示中文的方法

1 问题提出 使用图1所示的代码进行matplotlib绘图时&#xff0c;因为其默认不支持中文&#xff0c;此时无法显示正确内容&#xff0c;如图2所示。 图1 matplotlib绘图绘图代码 图2 matplotlib无法显示中文 2 问题解决 2.1 设置全局字体 在图1所示的代码中&#xff0c;第13…...

SQL Server2022详细安装教程

1. 打开SQL Server官网&#xff1a;SQL Server 下载 | Microsoft 2. 选择Developer版 3. 下载好安装包&#xff0c;打开&#xff0c;选择自定义 4. 选择下载位置&#xff0c;最好不要在C盘即主磁盘即可。等待下载 5. 下载成功之后会弹出这个框 6. 点击“安装”&#…...

家里温度随心控,假期出行更舒适~

春节假期马上到来啦&#xff01;这是放松身心、陪伴家人的最佳时机~      但旅途结束的温差变化、空气质量问题是否让你有些担忧呢&#xff1f;      别担心&#xff01;有了约克VRF中央空调&#xff0c;让你的假期更加舒心无忧~      清新空气&#xff0c;自在出游…...

压力测试详解

压力测试 压力测试是一种软件测试&#xff0c;用于验证软件应用程序的稳定性和可靠性。压力测试的目标是在极其沉重的负载条件下测量软件的健壮性和错误处理能力&#xff0c;并确保软件在危急情况下不会崩溃。它甚至可以测试超出正常工作点的测试&#xff0c;并评估软件在极端…...

从epoll事件的视角探讨TCP:三次握手、四次挥手、应用层与传输层之间的联系

目录 一、应用层与TCP之间的联系 二、 当通信双方中的一方如客户端主动断开连接时&#xff0c;仅是在客户端的视角下连接已经断开&#xff0c;在服务端的眼中&#xff0c;连接依然存在&#xff0c;为什么&#xff1f;——触发EPOLLRDHUP事件&#xff1a;对端关闭连接或停止写…...

Redis复制(replica)

Redis主从复制 [Redis主从复制]&#xff08;replica&#xff09;是一个多Redis实例进行数据同步的过程&#xff0c;其中一个实例是主实例&#xff08;Master&#xff09;&#xff0c;其他实例是从实例&#xff08;Slave&#xff09;。主实例负责处理命令请求&#xff0c;而从实…...

[云讷科技] 用于软件验证的仿真环境

我们使用Pursuit自动驾驶仪为各种场景设计仿真环境&#xff0c;以便用户可以在模拟环境中直接验证他们的软件&#xff0c;无需现场测试。该环境基于Gazebo引擎。 1. 工作区目录 模拟环境的工作区位于提供的U盘中的~/pursuit_space/sitl_space_pursuit中。用户可以按照用户手册…...

使用 Vite 和 Vue 框架创建组件库

在前端开发中&#xff0c;组件化开发已成为一种高效、可维护的方式。通过创建组件库&#xff0c;不仅可以提高代码复用率&#xff0c;还能方便地在不同项目之间共享组件。本文将详细介绍如何使用 Vite 和 Vue 框架创建一个组件库&#xff0c;并将其导出供其他项目使用。为保持一…...

【数据结构学习笔记】19:跳表(Skip List)

介绍 跳表是一个能在 O ( n l o g n ) O(nlogn) O(nlogn)时间完成查找、插入、删除的数据结构&#xff0c;相比于树形结构优点就是很好写&#xff08;所以也用于实现Redis ZSet&#xff09;。其核心思想就是维护一个元素有序的&#xff0c;能随机提升索引层数的链表。最下面一…...

【8】深入理解 Go 语言中的协程-从基础到高级应用

文章目录 一、引言 &#x1f31f;二、协程基础概念 &#x1f9d0;&#xff08;一&#xff09;什么是协程&#xff08;二&#xff09;协程与线程、进程的区别三、协程的创建与启动 &#x1f680;&#xff08;一&#xff09;使用 go 关键字创建协程&#xff08;二&#xff09;简单…...

深入理解 ECMAScript 2024 新特性:字符串 isWellFormed 方法

ECMAScript 2024 引入了一个新的字符串实例方法&#xff1a;String.prototype.isWellFormed。这一新增功能是为了帮助开发者更容易地验证字符串是否为有效的 Unicode 文本。本文将详细介绍这一方法的使用场景、实现原理及其在实际应用中的价值。 String.prototype.isWellFormed…...

算法分析与设计之贪心算法

文章目录 前言一、Greedy Algorithms1.1 贪心选择性质1.2 最优子结构性质1.3 正确性证明 二、典型例题2.1 Interval Scheduling间隔调度2.2 Interval Partitioning最少间教室排课2.3 Selecting Breakpoints选择加油站停靠点2.4 硬币找零2.5 Scheduling to Minimizing Lateness2…...

Centos 宝塔安装

yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh 安装成功界面 宝塔说明文档 https://www.bt.cn/admin/servers#wcu 或者可以注册宝塔账号 1 快速部署 安装docker 之后 2 需要在usr/bin下下载do…...

蓝桥与力扣刷题(709 转换成小写字母)

题目&#xff1a;给你一个字符串 s &#xff0c;将该字符串中的大写字母转换成相同的小写字母&#xff0c;返回新的字符串。 示例 1&#xff1a; 输入&#xff1a;s "Hello" 输出&#xff1a;"hello"示例 2&#xff1a; 输入&#xff1a;s "here…...

Redis的过期策略、内存淘汰机制

Redis只能存5G数据&#xff0c;可是你写了10G&#xff0c;那会删5G的数据。怎么删的&#xff1f;还有&#xff0c;你的数据已经设置了过期时间&#xff0c;但是时间到了&#xff0c;为什么内存占用率还是比较高? 一、Redis的过期策略 Redis采用的是定期删除惰性删除策略。 1…...

调用支付宝接口响应40004 SYSTEM_ERROR问题排查

在对接支付宝API的时候&#xff0c;遇到了一些问题&#xff0c;记录一下排查过程。 Body:{"datadigital_fincloud_generalsaas_face_certify_initialize_response":{"msg":"Business Failed","code":"40004","sub_msg…...

论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)

HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...

循环冗余码校验CRC码 算法步骤+详细实例计算

通信过程&#xff1a;&#xff08;白话解释&#xff09; 我们将原始待发送的消息称为 M M M&#xff0c;依据发送接收消息双方约定的生成多项式 G ( x ) G(x) G(x)&#xff08;意思就是 G &#xff08; x ) G&#xff08;x) G&#xff08;x) 是已知的&#xff09;&#xff0…...

【CSS position 属性】static、relative、fixed、absolute 、sticky详细介绍,多层嵌套定位示例

文章目录 ★ position 的五种类型及基本用法 ★ 一、position 属性概述 二、position 的五种类型详解(初学者版) 1. static(默认值) 2. relative(相对定位) 3. absolute(绝对定位) 4. fixed(固定定位) 5. sticky(粘性定位) 三、定位元素的层级关系(z-i…...

多模态商品数据接口:融合图像、语音与文字的下一代商品详情体验

一、多模态商品数据接口的技术架构 &#xff08;一&#xff09;多模态数据融合引擎 跨模态语义对齐 通过Transformer架构实现图像、语音、文字的语义关联。例如&#xff0c;当用户上传一张“蓝色连衣裙”的图片时&#xff0c;接口可自动提取图像中的颜色&#xff08;RGB值&…...

Spring Boot+Neo4j知识图谱实战:3步搭建智能关系网络!

一、引言 在数据驱动的背景下&#xff0c;知识图谱凭借其高效的信息组织能力&#xff0c;正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合&#xff0c;探讨知识图谱开发的实现细节&#xff0c;帮助读者掌握该技术栈在实际项目中的落地方法。 …...

GC1808高性能24位立体声音频ADC芯片解析

1. 芯片概述 GC1808是一款24位立体声音频模数转换器&#xff08;ADC&#xff09;&#xff0c;支持8kHz~96kHz采样率&#xff0c;集成Δ-Σ调制器、数字抗混叠滤波器和高通滤波器&#xff0c;适用于高保真音频采集场景。 2. 核心特性 高精度&#xff1a;24位分辨率&#xff0c…...

如何在网页里填写 PDF 表格?

有时候&#xff0c;你可能希望用户能在你的网站上填写 PDF 表单。然而&#xff0c;这件事并不简单&#xff0c;因为 PDF 并不是一种原生的网页格式。虽然浏览器可以显示 PDF 文件&#xff0c;但原生并不支持编辑或填写它们。更糟的是&#xff0c;如果你想收集表单数据&#xff…...

重启Eureka集群中的节点,对已经注册的服务有什么影响

先看答案&#xff0c;如果正确地操作&#xff0c;重启Eureka集群中的节点&#xff0c;对已经注册的服务影响非常小&#xff0c;甚至可以做到无感知。 但如果操作不当&#xff0c;可能会引发短暂的服务发现问题。 下面我们从Eureka的核心工作原理来详细分析这个问题。 Eureka的…...

Redis的发布订阅模式与专业的 MQ(如 Kafka, RabbitMQ)相比,优缺点是什么?适用于哪些场景?

Redis 的发布订阅&#xff08;Pub/Sub&#xff09;模式与专业的 MQ&#xff08;Message Queue&#xff09;如 Kafka、RabbitMQ 进行比较&#xff0c;核心的权衡点在于&#xff1a;简单与速度 vs. 可靠与功能。 下面我们详细展开对比。 Redis Pub/Sub 的核心特点 它是一个发后…...