重新理解?React?useRef原理
為什么要有 useRef?
React.useRef 是 React Hooks 中的一種,它提供了一種可以在函數(shù)組件中存儲(chǔ)可變值的方式。與 useState 不同,useRef 存儲(chǔ)的值不會(huì)引起組件的重新渲染。
我們使用 useRef 主要有以下幾個(gè)原因:
保存 DOM 元素的引用
在函數(shù)組件中,我們無(wú)法像類組件中那樣直接使用 this 來(lái)獲取 DOM 元素的引用。而 useRef 可以用來(lái)保存 DOM 元素的引用,方便我們獲取或修改其屬性。
保存組件的狀態(tài)
在函數(shù)組件中,每次組件重新渲染時(shí),所有的變量都會(huì)被重新聲明和初始化。為了在多次渲染之間保留一些數(shù)據(jù),我們可以使用 useRef 來(lái)保存這些數(shù)據(jù),它們?cè)诮M件的整個(gè)生命周期中保持不變。
避免重新渲染的性能問(wèn)題
在某些情況下,我們需要保存一些數(shù)據(jù),但是這些數(shù)據(jù)并不需要觸發(fā)重新渲染。如果使用 useState,每次更新這些數(shù)據(jù)都會(huì)觸發(fā)組件的重新渲染,從而浪費(fèi)性能。而使用 useRef 可以避免這個(gè)問(wèn)題。
在組件之間傳遞數(shù)據(jù)
在函數(shù)組件中,我們可以使用 useContext 或 useReducer 等鉤子來(lái)在組件之間傳遞數(shù)據(jù)。但是有些情況下,我們只需要簡(jiǎn)單地在組件之間傳遞一個(gè)變量或者一個(gè)函數(shù),此時(shí)使用 useRef 可以更加方便。
代碼示例
使用 useRef 存儲(chǔ)可變值:
import React, { useRef } from 'react'; function App() { const counterRef = useRef(0); function handleClick() { counterRef.current += 1; console.log(counterRef.current); } return ( <button onClick={handleClick}> Click me </button> ); }
在這個(gè)例子中,我們使用 useRef 創(chuàng)建了一個(gè)名為 counterRef 的變量,并初始化為 0。每次按鈕被點(diǎn)擊時(shí),我們都會(huì)將 counterRef.current 的值加 1,并將結(jié)果打印到控制臺(tái)中。
使用 useRef 存儲(chǔ) DOM 元素的引用:
import React, { useRef } from 'react'; function App() { const inputRef = useRef(null); function handleClick() { inputRef.current.focus(); } return ( <> <input type="text" ref={inputRef} /> <button onClick={handleClick}> Focus input </button> </> ); }
在這個(gè)例子中,我們使用 useRef 創(chuàng)建了一個(gè)名為 inputRef 的變量,并將其賦值為 null。在組件中,我們將 input 元素的 ref 屬性設(shè)置為 inputRef。每次按鈕被點(diǎn)擊時(shí),我們調(diào)用 inputRef.current.focus() 來(lái)將輸入框聚焦。
useRef 的特點(diǎn)
- 會(huì)返回一個(gè)可變的 ref 對(duì)象。
- 可以保存任何可變值,類似于在 class 組件中使用實(shí)例變量。
- 返回的 ref 對(duì)象在組件的整個(gè)生命周期中保持不變。
- 并不會(huì)在每次組件渲染時(shí)都生成新的 ref 對(duì)象,因此可以用來(lái)保存一些不需要觸發(fā)重新渲染的數(shù)據(jù)。
- 可以用來(lái)引用 DOM 元素,用于獲取或修改其屬性。
- 可以用來(lái)在函數(shù)組件之間傳遞數(shù)據(jù)。
- 可以模擬實(shí)例變量,用于保存函數(shù)組件中的狀態(tài)。
useRef 和 useState 的區(qū)別
useRef 和 useState 有以下幾個(gè)區(qū)別:
- useRef 返回的是一個(gè)可變的 ref 對(duì)象,而 useState 返回的是一個(gè)可變的 state 值和一個(gè)更新 state 的函數(shù)。
- useRef 主要用于保存一個(gè)可變值,并不會(huì)觸發(fā)組件重新渲染,而 useState 能夠觸發(fā)組件重新渲染。
- useRef 可以在組件渲染的過(guò)程中保持?jǐn)?shù)據(jù)的穩(wěn)定,而 useState 每次渲染都會(huì)重新計(jì)算 state 值。
- useRef 可以用于訪問(wèn) DOM 元素,而 useState 不能。
使用場(chǎng)景
具體使用場(chǎng)景和每個(gè)場(chǎng)景下的代碼示例:
存儲(chǔ)定時(shí)器的 ID
定時(shí)器是 JavaScript 中常見(jiàn)的一種異步操作。在函數(shù)組件中,我們可以使用 useRef 存儲(chǔ)定時(shí)器的 ID,以便在組件卸載時(shí)清除定時(shí)器。
import React, { useState, useEffect, useRef } from 'react'; function App() { const [count, setCount] = useState(0); const intervalRef = useRef(null); useEffect(() => { intervalRef.current = setInterval(() => { setCount(c => c + 1); }, 1000); return () => clearInterval(intervalRef.current); }, []); return ( <div> <p>{count}</p> <button onClick={() => clearInterval(intervalRef.current)}> Stop timer </button> </div> ); }
在這個(gè)例子中,我們使用 useRef 創(chuàng)建了一個(gè)名為 intervalRef 的變量,并將其初始化為 null。在 useEffect 中,我們使用 setInterval 創(chuàng)建了一個(gè)定時(shí)器,并將其 ID 存儲(chǔ)在 intervalRef.current 中。在組件卸載時(shí),我們使用 clearInterval 來(lái)清除定時(shí)器。點(diǎn)擊 Stop timer 按鈕時(shí),我們也會(huì)使用 clearInterval 來(lái)停止定時(shí)器。
存儲(chǔ)上一次的 props 或 state 值
有時(shí)候我們需要在組件更新時(shí)和之前的 props 或 state 進(jìn)行比較。在這種情況下,我們可以使用 useRef 存儲(chǔ)上一次的值。
import React, { useState, useEffect, useRef } from 'react'; function App() { const [count, setCount] = useState(0); const prevCountRef = useRef(null); useEffect(() => { prevCountRef.current = count; }); const prevCount = prevCountRef.current; return ( <div> <p>Current count: {count}</p> {prevCount && ( <p>Previous count: {prevCount}</p> )} <button onClick={() => setCount(c => c + 1)}> Increase count </button> </div> ); }
在這個(gè)例子中,我們使用 useRef 創(chuàng)建了一個(gè)名為 prevCountRef 的變量,并將其初始化為 null。在 useEffect 中,我們將 count 的值存儲(chǔ)在 prevCountRef.current 中。在組件更新時(shí),我們通過(guò) prevCountRef.current 獲取上一次的 count 值,并將其展示在頁(yè)面上。每次 count 更新時(shí),prevCountRef.current 的值也會(huì)被更新。
存儲(chǔ) DOM 元素的引用
在函數(shù)組件中,我們無(wú)法直接使用類組件中的 this.refs。因此,我們可以使用 useRef 存儲(chǔ) DOM 元素的引用,以便進(jìn)行 DOM 操作。
import React, { useRef } from 'react'; function App() { const inputRef = useRef(null); function handleFocus() { inputRef.current.style.backgroundColor = 'yellow'; } function handleBlur() { inputRef.current.style.backgroundColor = 'white'; } return ( <> <input type="text" ref={inputRef} onFocus={handleFocus} onBlur={handleBlur} /> <button onClick={() => inputRef.current.focus()}> Focus input </button> </> ); }
在這個(gè)例子中,我們使用 useRef 創(chuàng)建了一個(gè)名為 inputRef 的變量,并將其初始化為 null。在組件中,我們將 input 元素的 ref 屬性設(shè)置為 inputRef,并為 onFocus 和 onBlur 事件分別添加了 handleFocus 和 handleBlur 函數(shù)。在 handleFocus 函數(shù)中,我們將輸入框的背景顏色設(shè)置為黃色,在 handleBlur 函數(shù)中將其設(shè)置為白色。點(diǎn)擊 Focus input 按鈕時(shí),我們使用 inputRef.current.focus() 讓輸入框聚焦。
結(jié)語(yǔ)
React.useRef 提供了一種在函數(shù)組件中存儲(chǔ)可變值和 DOM 元素引用的方法。使用 useRef 可以讓我們?cè)诤瘮?shù)組件中實(shí)現(xiàn)更多的功能,并且不會(huì)引起組件的重新渲染。在使用 useRef 時(shí),需要注意不要濫用 useRef,只在必要的時(shí)候使用它,以避免造成代碼的混亂。
以上就是重新理解 React useRef的詳細(xì)內(nèi)容,更多關(guān)于重新理解 React useRef的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
react如何將字符串轉(zhuǎn)義成html語(yǔ)句
這篇文章主要介紹了react如何將字符串轉(zhuǎn)義成html語(yǔ)句問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-12-12React+Router多級(jí)導(dǎo)航切換路由方式
這篇文章主要介紹了React+Router多級(jí)導(dǎo)航切換路由方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-03-03React?Hooks中?useRef和useImperativeHandle的使用方式
這篇文章主要介紹了React?Hooks中?useRef和useImperativeHandle的使用方式,文中說(shuō)明了useRef和useCallback一起使用,?可以解決閉包陷阱的問(wèn)題,本文結(jié)合實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-10-10React中useState原理的代碼簡(jiǎn)單實(shí)現(xiàn)
要實(shí)現(xiàn)useState的背后原理,則需要深入了解狀態(tài)是如何在函數(shù)組件的渲染周期中保持和更新的,本文將通過(guò)一段代碼簡(jiǎn)單闡述useState鉤子函數(shù)的實(shí)現(xiàn)思路,希望對(duì)大家有所幫助2023-12-12React 無(wú)狀態(tài)組件(Stateless Component) 與高階組件
這篇文章主要介紹了React 無(wú)狀態(tài)組件(Stateless Component) 與高階組件,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-08-08React?Native?的動(dòng)態(tài)列表方案探索詳解
這篇文章主要為大家介紹了React?Native?的動(dòng)態(tài)列表方案探索示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09