React Hooks函数之useRef

2023-11-30 02:52

本文主要是介绍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 返回的是一个固定的引用,不会因为重新渲染而改变。

这篇关于React Hooks函数之useRef的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/435359

相关文章

Vue3 的 shallowRef 和 shallowReactive:优化性能

大家对 Vue3 的 ref 和 reactive 都很熟悉,那么对 shallowRef 和 shallowReactive 是否了解呢? 在编程和数据结构中,“shallow”(浅层)通常指对数据结构的最外层进行操作,而不递归地处理其内部或嵌套的数据。这种处理方式关注的是数据结构的第一层属性或元素,而忽略更深层次的嵌套内容。 1. 浅层与深层的对比 1.1 浅层(Shallow) 定义

这15个Vue指令,让你的项目开发爽到爆

1. V-Hotkey 仓库地址: github.com/Dafrok/v-ho… Demo: 戳这里 https://dafrok.github.io/v-hotkey 安装: npm install --save v-hotkey 这个指令可以给组件绑定一个或多个快捷键。你想要通过按下 Escape 键后隐藏某个组件,按住 Control 和回车键再显示它吗?小菜一碟: <template

【 html+css 绚丽Loading 】000046 三才归元阵

前言:哈喽,大家好,今天给大家分享html+css 绚丽Loading!并提供具体代码帮助大家深入理解,彻底掌握!创作不易,如果能帮助到大家或者给大家一些灵感和启发,欢迎收藏+关注哦 💕 目录 📚一、效果📚二、信息💡1.简介:💡2.外观描述:💡3.使用方式:💡4.战斗方式:💡5.提升:💡6.传说: 📚三、源代码,上代码,可以直接复制使用🎥效果🗂️目录✍️

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

hdu1171(母函数或多重背包)

题意:把物品分成两份,使得价值最接近 可以用背包,或者是母函数来解,母函数(1 + x^v+x^2v+.....+x^num*v)(1 + x^v+x^2v+.....+x^num*v)(1 + x^v+x^2v+.....+x^num*v) 其中指数为价值,每一项的数目为(该物品数+1)个 代码如下: #include<iostream>#include<algorithm>

计算机毕业设计 大学志愿填报系统 Java+SpringBoot+Vue 前后端分离 文档报告 代码讲解 安装调试

🍊作者:计算机编程-吉哥 🍊简介:专业从事JavaWeb程序开发,微信小程序开发,定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事,生活就是快乐的。 🍊心愿:点赞 👍 收藏 ⭐评论 📝 🍅 文末获取源码联系 👇🏻 精彩专栏推荐订阅 👇🏻 不然下次找不到哟~Java毕业设计项目~热门选题推荐《1000套》 目录 1.技术选型 2.开发工具 3.功能

Vue3项目开发——新闻发布管理系统(六)

文章目录 八、首页设计开发1、页面设计2、登录访问拦截实现3、用户基本信息显示①封装用户基本信息获取接口②用户基本信息存储③用户基本信息调用④用户基本信息动态渲染 4、退出功能实现①注册点击事件②添加退出功能③数据清理 5、代码下载 八、首页设计开发 登录成功后,系统就进入了首页。接下来,也就进行首页的开发了。 1、页面设计 系统页面主要分为三部分,左侧为系统的菜单栏,右侧

C++操作符重载实例(独立函数)

C++操作符重载实例,我们把坐标值CVector的加法进行重载,计算c3=c1+c2时,也就是计算x3=x1+x2,y3=y1+y2,今天我们以独立函数的方式重载操作符+(加号),以下是C++代码: c1802.cpp源代码: D:\YcjWork\CppTour>vim c1802.cpp #include <iostream>using namespace std;/*** 以独立函数

【VUE】跨域问题的概念,以及解决方法。

目录 1.跨域概念 2.解决方法 2.1 配置网络请求代理 2.2 使用@CrossOrigin 注解 2.3 通过配置文件实现跨域 2.4 添加 CorsWebFilter 来解决跨域问题 1.跨域概念 跨域问题是由于浏览器实施了同源策略,该策略要求请求的域名、协议和端口必须与提供资源的服务相同。如果不相同,则需要服务器显式地允许这种跨域请求。一般在springbo

HTML提交表单给python

python 代码 from flask import Flask, request, render_template, redirect, url_forapp = Flask(__name__)@app.route('/')def form():# 渲染表单页面return render_template('./index.html')@app.route('/submit_form',