在 React 中,我們經常使用 useState 來管理組件的狀態,並讓組件隨著狀態的變化重新渲染。不過在某些情況,不希望狀態變更時觸發重新渲染,這時就可以使用 useRef 來保存狀態,或是引用 DOM 元素來操作。
useRef 基本語法當你呼叫 useRef 時,它會回傳一個包含 current 屬性的物件。這個 current 可以用來保存我們想要記住的值,且不會隨著重新渲染而丟失。
const ref = useRef(initialValue);
initialValue 是用來設定 current 的初始值。useRef 返回的物件(ref)中的 current 屬性會保存這個值。useRef 的使用時機當我們需要在 React 中保存某些資料,但不希望資料變更時觸發組件的重新渲染,可以使用 useRef。一個常見的例子是儲存表單中的輸入值,或是在某個事件觸發時保存資料,這些資料不會影響畫面的顯示。
useRef 也可以用來存取 DOM 元素的引用。在 React 中,很少直接操作 DOM 元素,例如用document.querySelector的方式取得DOM,但在某些情況下,操作 DOM 是會需要用到的。例如,當需要聚焦到某個表單輸入欄位,或滾動到特定位置時,可以使用 useRef 來存取該元素的 DOM 引用。
useRef 保存狀態useState 每次變更狀態時,會觸發重新渲染組件,但有些狀態我們並不想讓它引發重新渲染。使用 useRef 可以避免這個問題。
範例:用 useRef 來實作一個不會觸發重新渲染的計數器:
import React, { useRef, useState } from 'react';
function Counter() {
const countRef = useRef(0); // 使用 useRef 保存計數器值
const [renderCount, setRenderCount] = useState(0); // 控制組件重新渲染的狀態
const incrementCount = () => {
countRef.current += 1; // 使用 useRef 的 current 更新計數器值
console.log("計數器值:", countRef.current);
};
return (
<div>
<p>計數器值不會觸發重新渲染: {countRef.current}</p>
<p>畫面重新渲染次數: {renderCount}</p>
<button onClick={incrementCount}>增加計數器值</button>
<button onClick={() => setRenderCount(renderCount + 1)}>強制重新渲染</button>
</div>
);
}
export default Counter;
在這個範例中,countRef 儲存了計數器的值,但它並不會觸發重新渲染。即便點擊「增加計數器值」按鈕,畫面顯示的數值也不會變動;要強制重新渲染,則可以點擊「強制重新渲染」按鈕。這顯示了 useRef 不會觸發重新渲染的特性。
當按下七次計數器之後,只有在 console.log 上顯示,畫面卻沒有更新。

但用 useState 的值更新後,countRef 的值就會被更新到畫面上。

useRef 存取 DOM 元素useRef 的另一個常見用途是直接存取 DOM 元素。我們可以用 useRef 來引用 HTML 元素,並進行聚焦、滾動等 DOM 操作。
當組件渲染後,我們可以使用 useRef 來讓一個輸入框自動獲得焦點。
import React, { useRef, useEffect } from 'react';
function AutoFocusInput() {
const inputRef = useRef(null); // 使用 useRef 來引用 DOM 元素
useEffect(() => {
inputRef.current.focus(); // 當組件渲染後,讓輸入框自動獲得焦點
}, []);
return (
<div>
<input ref={inputRef} placeholder="自動聚焦的輸入框" />
</div>
);
}
export default AutoFocusInput;
在這個範例中,我們使用了 inputRef 來引用輸入框,並在 useEffect 中讓這個輸入框在組件渲染後自動獲得焦點。這就是操作 DOM 元素的典型用法。
useRef 能夠幫助我們:
useRef 提供了方便的引用方式。與 useState 不同,useRef 不會觸發組件的重新渲染。當我們需要記住一些資料而不影響 UI 的時,useRef 是一個理想的選擇。另外再需要操作 DOM 元素時也能應用到。
本文將會同步更新到我的部落格