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.pswp.cn/news/168004.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/168004.shtml
英文地址,請注明出處:http://en.pswp.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.…