React第十七章(useRef)

useRef

当你在React中需要处理DOM元素或需要在组件渲染之间保持持久性数据时,便可以使用useRef。

import { useRef } from 'react';
const refValue = useRef(initialValue)
refValue.current // 访问ref的值 类似于vue的ref,Vue的ref是.value,其次就是vue的ref是响应式的,而react的ref不是响应式的

通过Ref操作DOM元素

参数
  • initialValue:ref 对象的 current 属性的初始值。可以是任意类型的值。这个参数在首次渲染后被忽略。
返回值
  • useRef返回一个对象,对象的current属性指向传入的初始值。 {current:xxxx}
注意
  • 改变 ref.current 属性时,React 不会重新渲染组件。React 不知道它何时会发生改变,因为 ref 是一个普通的 JavaScript 对象。
  • 除了 初始化 外不要在渲染期间写入或者读取 ref.current,否则会使组件行为变得不可预测。
import { useRef } from "react"
function App() {//首先,声明一个 初始值 为 null 的 ref 对象let div = useRef(null)const heandleClick = () => {//当 React 创建 DOM 节点并将其渲染到屏幕时,React 将会把 DOM 节点设置为 ref 对象的 current 属性console.log(div.current)}return (<>{/*然后将 ref 对象作为 ref 属性传递给想要操作的 DOM 节点的 JSX*/}<div ref={div}>dom元素</div><button onClick={heandleClick}>获取dom元素</button></>)
}
export default App

数据存储

我们实现一个保存count的新值和旧值的例子,但是在过程中我们发现一个问题,就是num的值一直为0,这是为什么呢?

因为等useStateSetCount执行之后,组件会重新rerender,num的值又被初始化为了0,所以num的值一直为0。

import React, { useLayoutEffect, useRef, useState } from 'react';function App() {let num = 0let [count, setCount] = useState(0)const handleClick = () => {setCount(count + 1)num = count;};return (<div><button onClick={handleClick}>增加</button><div>{count}:{num}</div></div>);
}export default App;

在这里插入图片描述

如何修改?

我们可以使用useRef来解决这个问题,因为useRef只会在初始化的时候执行一次,当组件reRender的时候,useRef的值不会被重新初始化。

import React, { useLayoutEffect, useRef, useState } from 'react';function App() {let num = useRef(0)let [count, setCount] = useState(0)const handleClick = () => {setCount(count + 1)num.current = count;};return (<div><button onClick={handleClick}>增加</button><div>{count}:{num.current}</div></div>);
}export default App;

在这里插入图片描述

实际应用

我们实现一个计时器的例子,在点击开始计数的时候,计时器会每300ms执行一次,在点击结束计数的时候,计时器会被清除。

问题

我们发现,点击end的时候,计时器并没有被清除,这是为什么呢?

原因

这是因为组件一直在重新ReRender,所以timer的值一直在被重新赋值为null,导致无法清除计时器。

import React, { useLayoutEffect, useRef, useState } from 'react';function App() {console.log('render')let timer: NodeJS.Timeout | null = nulllet [count, setCount] = useState(0)const handleClick = () => {timer = setInterval(() => {setCount(count => count + 1)}, 300)};const handleEnd = () => {console.log(timer);if (timer) {clearInterval(timer)timer = null}};return (<div><button onClick={handleClick}>开始计数</button><button onClick={handleEnd}>结束计数</button><div>{count}</div></div>);
}export default App;
如何修改?

我们可以使用useRef来解决这个问题,因为useRef的值不会因为组件的重新渲染而改变。

import React, { useLayoutEffect, useRef, useState } from 'react';function App() {console.log('render')let timer = useRef<null | NodeJS.Timeout>(null)let [count, setCount] = useState(0)const handleClick = () => {timer.current = setInterval(() => {setCount(count => count + 1)}, 300)};const handleEnd = () => {if (timer.current) {clearInterval(timer.current)timer.current = null}};return (<div><button onClick={handleClick}>开始计数</button><button onClick={handleEnd}>结束计数</button><div>{count}</div></div>);
}export default App;

注意事项

  1. 组件在重新渲染的时候,useRef的值不会被重新初始化。

  2. 改变 ref.current 属性时,React 不会重新渲染组件。React 不知道它何时会发生改变,因为 ref 是一个普通的 JavaScript 对象。

  3. useRef的值不能作为useEffect等其他hooks的依赖项,因为它并不是一个响应式状态。

  4. useRef不能直接获取子组件的实例,需要使用forwardRef。

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

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

相关文章

【C++】内存分布、new、delete、 operator new、operator delete

内存分布 在C语言和C中&#xff0c;程序内存被划分成六个部分&#xff1a; 内核空间、栈、内存映射段、堆、数据段、代码段 栈&#xff1a;又称堆栈&#xff0c;主要为非静态局部变量、函数参数、返回值等&#xff0c;栈的生长方向是向下生长的 内存映射段&#xff1a;高效的…

混合云策略在安全领域受到青睐

Genetec 发布了《2025 年物理安全状况报告》&#xff0c;该报告根据超过 5,600 名该领域领导者&#xff08;其中包括 100 多名来自澳大利亚和新西兰的领导者&#xff09;的回应&#xff0c;揭示了物理安全运营的趋势。 报告发现&#xff0c;澳大利亚和新西兰的组织采用混合云策…

FastAPI解决跨域报错net::ERR_FAILED 200 (OK)

目录 一、跨域问题的本质 二、FastAPI中的CORS处理 1. 安装FastAPI和CORS中间件 2. 配置CORS中间件 3. 运行FastAPI应用 三、解决跨域报错的步骤 四、案例:解决Vue.js与FastAPI的跨域问题 1. Vue.js前端应用 2. FastAPI后端API 3. 配置CORS中间件 4. 运行和测试 五…

霍尔效应电流传感器

适用于大电流&#xff0c;低功耗的电流检测&#xff1a; TVS选型: RS232的隔离电路: 单片机采集200伏高压 如何做隔离电路&#xff1a; 采用线性光电耦合器HCNR200实现高压直流母线电压的精确采样。还是用电阻分压&#xff0c;只是在ADC检测阶段加上隔离芯片&#xff1a;

【计网笔记】习题

物理层 不属于物理层接口规范定义范畴的是&#xff08;C&#xff09; A. 接口形状 B. 引脚功能 C. 物理地址 D. 信号电平 【2023-912】光网络只能通过导向型介质传播。&#xff08;&#xff09; 【2017-408】若信道在无噪声情况下的极限数据传输速率不小于信噪比为30dB条件下的…

最新 AI 编程工具全面对比:v0、Bolt.new、Cursor、Windsurf

随着人工智能的快速发展&#xff0c;越来越多的 AI 驱动的开发工具应运而生&#xff0c;旨在提升开发效率、优化开发流程&#xff0c;并减轻开发者的工作负担。在这个背景下&#xff0c;四款新兴的 AI 编程工具&#xff1a;v0、Bolt.new、Cursor 和 Windsurf&#xff0c;各具特…

【C++算法】35.位运算_两整数之和

文章目录 题目链接&#xff1a;题目描述&#xff1a;解法C 算法代码&#xff1a; 题目链接&#xff1a; 371. 两整数之和 题目描述&#xff1a; 解法 笔试的话直接 return ab&#xff1b; 接下来讲一下这题的解法&#xff1a; 位运算&#xff08;异或运算-无进位相加&#xff…

PyCharm+Selenium+Pytest配置小记

1、下载ChromeDriver&#xff1a; Chrome130以后的Driver下载&#xff1a; Chrome for Testing availabilityhttps://googlechromelabs.github.io/chrome-for-testing/ &#xff08;1&#xff09;查看自己Crome浏览器的版本&#xff1a;设置-->关于 Chrome&#xff1b; &…

如何在UI自动化测试中创建稳定的定位器?

如何在UI自动化测试中创建稳定的定位器&#xff1f; 前言1. 避免使用绝对路径2. 避免在定位器中使用索引3. 避免多个类名的定位器4. 避免动态和自动生成的ID5. 确保定位器唯一6. 处理隐藏元素的策略7. 谨慎使用基于文本的定位器8. 使用AI创建稳定的定位器 总结 前言 在自动化测…

明日宣讲 香港科技大学广州|数据科学与分析学域硕博招生宣讲会【湖南大学专场】

&#x1f4e3;&#x1f4e3;&#x1f4e3;明日宣讲 香港科技大学广州&#xff5c;数据科学与分析学域硕博招生宣讲会【湖南大学专场】 时间&#xff1a;2024年12月10日&#xff08;星期二&#xff09;15:00 地点&#xff1a;湖南大学信息科学与工程学院624会议室 报名链接&…

BurpSuite-8(FakeIP与爬虫审计)

声明&#xff1a;学习视频来自b站up主 泷羽sec&#xff0c;如涉及侵权马上删除文章 感谢泷羽sec 团队的教学 视频地址&#xff1a;IP伪造和爬虫审计_哔哩哔哩_bilibili 一、FakeIP 1.配置环境 BurpSuite是java环境下编写的&#xff0c;而今天的插件是python编写的&#xff0c…

Qt C++ 显示多级结构体,包括结构体名、变量名和值

文章目录 mainwindow.hmainwindow.cppstructures.hmain.cpp QTreeView 和 QStandardItemModel 来实现。以下是实现这一功能的步骤和示例代码&#xff1a; 定义多级结构体&#xff1a; 假设你有一个多级结构体&#xff0c;如下所示&#xff1a; struct SubStruct {int subValue…

linux基于systemd自启守护进程 systemctl自定义服务傻瓜式教程

系统服务 书接上文: linux自启任务详解 演示系统:ubuntu 20.04 开发部署项目的时候常常有这样的场景: 业务功能以后台服务的形式提供,部署完成后可以随着系统的重启而自动启动;服务异常挂掉后可以再次拉起 这个功能在ubuntu系统中通常由systemd提供 如果仅仅需要达成上述的场…

ros项目dual_arm_pick-place(moveit和gazebo联合仿真)(一)

目录 前言正文创建功能包具体代码运行 总结 前言 dual_arm_pick-place项目中&#xff0c;实现了两套的moveit和gazebo联合仿真。 启动文件分别是bringup_moveit.launch和arm_bringup_moveit.launch。 在这个项目中&#xff0c;我将代码重新创建了一个包&#xff0c;co_simula…

MySQL 索引(B+树)详解

MySQL 索引&#xff08;B树&#xff09;详解 MySQL逻辑架构对比InnoDB与MyISAM存储结构存储空间可移植性、备份及恢复事务支持AUTO_INCREMENT表锁差异全文索引表主键表的具体行数CRUD操作外键 sql优化简介什么情况下进行sql优化sql语句执行过程sql优化就是优化索引 索引索引的优…

MySQL生产环境备份脚本

全量备份脚本&#xff0c;其中BakDir&#xff0c;ZlbakDir&#xff0c;LogFile需要自己创建 #!/bin/bash export LANGen_US.UTF-8# 指定备份目录 BakDir/root/beifen/data/mysqlbak/data/allbak # 指定增量备份目录 ZlbakDir/root/beifen/data/mysqlbak/data/zlbak # 备份日志…

HTTP multipart/form-data 请求

序言 最近在写项目的过程中有一个需求是利用 HTTP 协议传输图片和视频&#xff0c;经过查询方法相应的方法发现使用 multipart/form-data 的方式&#xff0c;这是最常见处理二进制文件的表单编码类型。  学习了一下午&#xff0c;现在总结一下使用的方法和相关的知识点&#x…

Linux下redis环境的搭建

1.redis的下载 redis官网下载redis的linux压缩包&#xff0c;官网地址:Redis下载 网盘链接&#xff1a; 通过网盘分享的文件&#xff1a;redis-5.0.4.tar.gz 链接: https://pan.baidu.com/s/1cz3ifYrDcHWZXmT1fNzBrQ?pwdehgj 提取码: ehgj 2.redis安装与配置 将包上传到 /…

day09性能测试(1)——纯理论

document.querySelector(video).playbackRate 2.5 //可以写任何数字 【没有所谓的运气&#x1f36c;&#xff0c;只有绝对的努力✊】 目录 1、性能测试概念 2、功能测试 vs 性能测试 3、小结&#xff08;习题&#xff09; 4、性能测试的策略 4.1 基准测试 4.2 负载测试 …

内部类和Object类

匿名对象 格式&#xff1a; 匿名对象只可以调用一次成员 &#xff1a; 1. 调用一次成员变量 &#xff1a; new 类名(实参).成员变量名&#xff1b; 2.调用一次成员方法&#xff1a; new 类名(实参).成员方法名(实参)&#xff1b; 匿名对象存在的必要&#xff1a;为了提高…