React Hooks函数之useRef

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

以下是一些使用 useRef 的场景和示例:

1、存储React DOM 元素

我们首先回忆一下 vue 中的 ref:

        ref 被用来给元素或子组件注册引用信息 —— vue 官网。引用信息将会注册在父组件的 $refs 对象上。

请看示例:

<!-- `vm.$refs.p` will be the DOM node -->
<p ref="p">hello</p><!-- `vm.$refs.child` will be the child component instance -->
<child-component ref="child"></child-component>

        如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例。

那么 react 中的 ref 是否也是这个作用?我们可以从其用法上去做判断。

React 支持一个特殊的、可以附加到任何组件上的 ref 属性。此属性可以是一个由 React.createRef() 函数创建的对象、或者一个回调函数、或者一个字符串(遗留 API) —— 官网-ref

        于是我们知道在 react 中 ref 属性可以是一个对象、回调函数,亦或一个字符串。

1.1、useRef使用

  存储React元素:你可以使用 useRef 来存储一个React元素,然后在需要的时候使用这个元素。这在一些情况下很有用,比如你需要引用一个在组件的子元素列表中的特定元素。

简单示例:

import { useRef, useEffect } from 'react';function MyComponent() {const inputRef = useRef(null);useEffect(() => {inputRef.current.focus(); //组件挂载时使其获得焦点}, []);return (<div><input type="text" ref={inputRef} /></div>);
}

上面的代码使用 useRef 获取 input 元素的引用,并在组件挂载时使其获得焦点。

1.2、对比类组件中的refs

1.2.1、String 类型的 Refs

下面这个例子将 ref 分别应用在 dom 元素子组件中:

class ASpan extends React.Component {render() {return <span>click</span>}
}class EventDemo1 extends React.Component {handleClick() {console.log(this.refs)console.log(this.refs.aButton.innerHTML)}render() {return (// 箭头函数<button ref="aButton" onClick={() => this.handleClick()}><ASpan ref="aSpan" /></button>);}
}

点击按钮,控制台输出:

{aSpan: ASpan, aButton: button}
<span>click</span>

Tip:用法上和 vue 中的 vm.$refs 非常相似。

:如果你目前还在使用 this.refs.textInput 这种方式访问 refs ,我们建议用回调函数或 createRef API 的方式代替 —— 官网-过时 API:String 类型的 Refs

1.2.2、回调 Refs

React 也支持另一种设置 refs 的方式,称为“回调 refs”。它能助你更精细地控制何时 refs 被设置和解除 —— 官网-回调 Refs

将字符串式 Refs 示例改成回调式。请看示例:

class EventDemo1 extends React.Component {handleClick() {console.log(this.refs)console.log(this.button.innerHTML)}setButtonRef = (element) => {this.button = element}render() {return (// 使用 `ref` 的回调函数将按钮 DOM 节点的引用存储到 React// 实例上(比如 this.button)<button ref={this.setButtonRef} onClick={() => this.handleClick()}>click</button>);}
}

点击按钮,控制台输出:

{}
click

        回调函数中接受 React 组件实例或 HTML DOM 元素作为参数,以使它们能在其他地方被存储和访问。

1.2.3、内联函数

可以将 refs 回调函数直接写在 ref 中。就像这样:

// 与上面示例效果相同
<button ref={element => this.button = element} onClick={() => this.handleClick()}>click
</button>
1.2.4、关于回调次数

如果 ref 回调函数是以内联函数的方式定义的,在更新过程中它会被执行两次,第一次传入参数 null,然后第二次会传入参数 DOM 元素 —— 官网-关于回调 refs 的说明

请看示例:

class EventDemo1 extends React.Component {state = { date: new Date() }constructor() {super()setInterval(() => {this.setState({ date: new Date() })}, 3000)}render() {return (<button ref={element => { this.button = element; console.log('ref'); }}>click {this.state.date.toLocaleTimeString()}</button>);}
}

首先输出 ref,然后每过 3 秒就会输出 2 次 ref

Tip:大多数情况下它是无关紧要的 —— 官网

1.2.5、createRef API

将回调 refs 的例子改成 createRef 形式。请看示例:

class EventDemo1 extends React.Component {constructor() {super()this.button = React.createRef()// this.textInput = React.createRef()}handleClick() {// dom 元素或子组件可以在 ref 的 current 属性中被访问console.log(this.button.current.innerHTML)}render() {return (<button ref={this.button} onClick={() => this.handleClick()}>click</button>)}
}

每点击一下 button,控制台将输出一次 click

Refs 是使用 React.createRef() 创建的,并通过 ref 属性附加到 React 元素。在构造组件时,通常将 Refs 分配给实例属性,以便可以在整个组件中引用它们 —— 官网-创建 Refs

如果需要在增加一个 ref,则需要再次调用 React.createRef()

1.2.6、在函数组件中使用 ref

你不能在函数组件上使用 ref 属性,因为他们没有实例 —— 官网-访问 Refs

而通过 useRef Hook 能让我们在函数组件使用 ref。重写 class 组件 EventDemo1:

function EventDemo1() {const button = React.useRef(null)function handleClick() {console.log(button.current.innerHTML)}return (<button ref={button} onClick={() => handleClick()}>click</button>)
}

每点击一下 button,控制台将输出一次 click

const refContainer = useRef(initialValue);

useRef 返回一个可变的 ref 对象,其 .current 属性被初始化为传入的参数(initialValue) —— 官网-useref       

2、缓存值(存在整个生命周期中)

        存储一个变量或者常量:你可以使用 useRef 来存储一个变量或常量,以便在组件的整个生命周期中使用。

  useEffect里面的state的值,是固定的,这个是有办法解决的,就是用useRef,可以理解成useRef的一个作用:就是相当于全局作用域,一处被修改,其他地方全更新。

        本质上,useRef 就像是可以在其 .current 属性中保存一个可变值的“盒子”。你应该熟悉 ref 这一种访问 DOM 的主要方式。如果你将 ref 对象以 <div ref={myRef} /> 形式传入组件,则无论该节点如何改变,React 都会将 ref 对象的 .current 属性设置为相应的 DOM 节点。然而,useRef() 比 ref 属性更有用。它可以很方便地保存任何可变值,其类似于在 class 中使用实例字段的方式。

        请记住,当 ref 对象内容发生变化时,useRef 并不会通知你。变更 .current 属性不会引发组件重新渲染。如果想要在 React 绑定或解绑 DOM 节点的 ref 时运行某些代码,则需要使用回调 ref 来实现。

import { useRef, useEffect } from 'react';function MyComponent() {const prevCountRef = useRef(0);const [count, setCount] = useState(0);useEffect(() => {prevCountRef.current = count;}, [count]);return (<div><p>prev count: {prevCountRef.current}</p><p>current count: {count}</p><button onClick={() => setCount(count + 1)}>Increment</button></div>);
}

        在这个例子中,我们使用 useState 来存储一个计数器的值,同时也使用 useRef 来创建一个引用缓存了 count 的前一个值,以便在组件的整个生命周期中访问这个值。当我们点击按钮count 更新时,同时 prevCountRef.current 的值也会更新。注意,虽然 prevCountRef.current 的值会随着 count 的变化而变化,但 prevCountRef本身是一个可变的引用,我们可以在任何地方通过prevCountRef.current 来获取当前的值,用于记录前一次渲染的状态。

3、在 useEffect 中获取最新的值

import { useRef, useEffect } from 'react';function MyComponent(props) {const prevPropsRef = useRef(null);useEffect(() => {prevPropsRef.current = props;});// ...return (// ...);
}

        上面的代码使用 useRef 缓存了 props 的前一个值,可以用于比较前后两次 props 的变化情况。

使用 useRef 的原因是,在函数组件中使用普通的变量无法保证变量值的实时性,因为每次重新渲染组件时,普通变量都会重新声明,而 useRef 返回的是一个固定的引用,不会因为重新渲染而改变。

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

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

相关文章

Mathorcup数学建模竞赛第一届-【妈妈杯】B题:图像识别

目录 知识储备 传统图像处理方法进行瑕疵检测 传统算法方向的选择 瑕疵检测关注的两个问题 瑕疵的标注

【技术分享】RK3399 Ubuntu通过Python实现录音和播放功能

​本文基于IDO-SBC3968 Ubuntu 系统通过Python脚本实现录音和播放功能。 IDO-SBC3968采用RK3399国产六核64位CPU高性能处理器&#xff0c;支持4K HDMI2.0显示&#xff0c;接口丰富&#xff0c;拥有千兆以太网&#xff0c;全协议TypeC接口&#xff0c;USB3.0 &#xff0c;eDP 和…

Redis高并发缓存架构

前言&#xff1a; 针对缓存我们并不陌生&#xff0c;而今天所讲的是使用redis作为缓存工具进行缓存数据。redis缓存是将数据保存在内存中的&#xff0c;而内存的珍贵性是不可否认的。所以在缓存之前&#xff0c;我们需要明确缓存的对象&#xff0c;是否有必要缓存&#xff0c;怎…

ElasticSearch之配置

ElasticSearch主要的配置文件&#xff0c;如下&#xff1a; elasticsearch.yml&#xff0c;ElasticSearch的相关参数。jvm.options&#xff0c;JVM的相关参数。log4j2.properties&#xff0c;日志的相关参数。 默认情况下&#xff0c;ElasticSearch从$ES_HOME/config目录下读…

1 动态规划解不同的子序列

来源&#xff1a; LeetCode第115题 难度&#xff1a; 困难 问题描述 给定一个字符串S和一个字符串t&#xff0c;计算在S的子序列中t出现的个数。 注解&#xff1a; 字符串的一个子序列是指&#xff0c;通过删除一些(也可以不删除)字符且不干扰剩余字符的相对位置所组成的…

2022年03月 Scratch(三级)真题解析#中国电子学会#全国青少年软件编程等级考试

Scratch等级考试(1~4级)全部真题・点这里 一、单选题(共25题,每题2分,共50分) 第1题 以下四个选项中,运行哪个积木块,可能得到523这个数值? A: B: C: D: 答案:B 四个选项都遵循统一的公式:随机数ⅹ10+3=523,因此可以得出随

ZXing创建二维码位图

Android生成二维码通常使用ZXing库&#xff0c;其中提供了QRCodeWriter类。QRCodeWriter可将字符串编译为位矩阵BitMatrix&#xff0c;然后我们可以将位矩阵转为Int数组&#xff0c;通过bitmap.setPixels()方法将数组绘制于位图上。 1. 添加依赖 //Gradle Scripts -> buil…

和数集团出席中科院上海高研院​第三十三期“高研交叉论坛”信息能源融合专场

2023年11月21日&#xff0c;中国科学院上海高等研究院第三十三期“高研交叉论坛”信息能源融合专场在上海高研院成功举办。本次论坛由中国科学院上海高等研究院智能信息通信技术研究与发展中心、中国科学院低碳转化科学与工程重点实验室、中科院和数智能区块链与能源系统应用联…

【文末送书】机器学习高级实践

2023年初是人工智能爆发的里程碑式的重要阶段&#xff0c;以OpenAI研发的GPT为代表的大模型大行其道&#xff0c;NLP领域的ChatGPT模型火爆一时&#xff0c;引发了全民热议。而最新更新的GPT-4更是实现了大型多模态模型的飞跃式提升&#xff0c;它能够同时接受图像和文本的输入…

仿 美图 / 饿了么,店铺详情页功能

前言 UI有所不同&#xff0c;但功能差不多&#xff0c;商品添加购物车功能 正在写&#xff0c;写完会提交仓库。 效果图一&#xff1a;左右RecyclerView 联动 效果图二&#xff1a;通过点击 向上偏移至最大值 效果图三&#xff1a;通过点击 或 拖动 展开收缩公告 效果图四&…

SpringBoot3核心原理

SpringBoot3核心原理 事件和监听器 生命周期监听 场景&#xff1a;监听应用的生命周期 可以通过下面步骤自定义SpringApplicationRunListener来监听事件。 ①、编写SpringApplicationRunListener实现类 ②、在META-INF/spring.factories中配置org.springframework.boot.Sprin…

上市公司-股权性质数据(国企、央企)2003-2022年

上市公司-股权性质数据&#xff08;国企、央企&#xff09;是一个针对上市公司的数据集&#xff0c;主要涵盖了A股公司股权性质的详细信息&#xff0c;区分了公司是否为民营企业、国企或央企。这份数据集提供了每家上市公司的股权结构背景&#xff0c;对投资者、市场分析师和经…

Shell循环:for(二)

一、通过用户列表文件创建用户 需求&#xff1a;通过用户列表文件创建用户 [rootlocalhost ~]# cat user.txt qian yoa huang演示&#xff1a; [rootlocalhost ~]# vim foruser.sh #编写脚本 #!/bin/bash for i in cat user.txt do useradd $i if [ $? -eq 0 ] thenech…

2023年亚太杯数学建模C题新能源汽车成品文章(思路模型代码成品)

一、翻译 新能源汽车是指采用先进的技术原理、新技术和新结构&#xff0c;以非常规车用燃料&#xff08;非常规车用燃料是指汽油和柴油以外的燃料(非常规车用燃料是指汽油和柴油以外的燃料&#xff09;&#xff0c;并集成了汽车动力控制和驱动等先进技术的汽车。新能源汽车包括…

C++入门第九篇---Stack和Queue模拟实现,优先级队列

前言&#xff1a; 我们已经掌握了string vector list三种最基本的数据容器模板&#xff0c;而对于数据结构的内容来说&#xff0c;其余的数据结构容器基本都是这三种容器的延申和扩展&#xff0c;在他们的基础上扩展出更多功能和用法&#xff0c;今天我们便来模拟实现一下C库中…

superset 后端增加注册接口

好烦啊-- &#xff1a;< 1.先定义modes: superset\superset\models\user.py # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information…

Tars框架 Tars-Go 学习

Tars 框架安装 网上安装教程比较多&#xff0c;官方可以参数这个 TARS官方文档 (tarsyun.com) 本文主要介绍部署应用。 安装完成后Tars 界面 增加应用amc 部署申请 amc.GoTestServer.GoTestObj 名称不知道的可以参考自己创建的app config 点击刷新可以看到自己部署的应用 服…

获取当日的日期三个月后的日期

使用 java.time.LocalDate 类进行计算 import java.time.LocalDate;public class ThreeMonthsLaterExample {public static void main(String[] args) {// 获取当前日期LocalDate currentDate LocalDate.now();// 添加三个月LocalDate threeMonthsLater currentDate.plusMont…

【阿里云服务器】2023安装宝塔面板8.0.4

文章目录 前言安装宝塔远程链接服务器输入安装宝塔命令放行宝塔端口 一键安装环境附录重装系统Linux系统卸载宝塔方式一方式二 遇见的问题 前言 镜像是CentOS 7.9.4 安装宝塔 远程链接服务器 输入安装宝塔命令 yum install -y wget && wget -O install.sh https://…

Android 13.0 系统settings系统属性控制一级菜单显示隐藏

1.概述 在13.0的系统rom定制化开发中,系统settings的一级菜单有些在客户需求中需要去掉不显示,所以就需要通过系统属性来控制显示隐藏, 从而达到控制一级菜单的显示的目的,而系统settings是通过静态加载的方式负责显示隐藏,接下来就来实现隐藏显示一级菜单的 功能实现 2.…