Skip to main content

React Hook - useRef

useRef 是一個 React Hook,可以參考一個值且不會受到重新渲染影響

useRef 可以看作是不會觸發重新渲染的 useState

const ref = useRef(initialValue);

基本概念和用法

  • useRef 會回傳一個物件,此物件會有一個 current 的屬性裡面存放值
  • 每次渲染 useRef 的回傳值(物件)都是同一個(相同的 reference)
  • initialValue 為 ref 回傳物件的 current 屬性的初始值,可以是任何型別
  • ref.current 變化時,不會觸發 re-render

舉例來說: 下面程式碼,倘若點擊 Increment 按鈕,觸發 handleIncrement 函式,這時候 console 印出來值為 1,但因為畫面不會重新渲染,因此,畫面上仍然維持 Count: 0

const counter = () => {
const countRef = useRef(0);
const handleIncrement = () => {
countRef.current++;
console.log("Ref", countRef.current); // Ref: 1
};
return (
<div>
Count: {countRef.current}
<button onClick={handleIncrement}>Increment</button>
</div>
);
};

常見用法

  1. 紀錄元件資料狀態,不受渲染影響(ex:計算元件渲染次數)
const [name, setName] = useState("");
const renderCount = useRef(1);

useEffect(() => {
renderCount.current += 1;
});

return (
<div>
<input value={name} onChange={(e) => setName(e.target.value)} />
<div>我的名字是 {name}</div>
<div>重新渲染了 {renderCount}</div>
</div>
);
  1. 透過 ref 選取操作虛擬 DOM 元素(ex:聚焦文字輸入框)

使用 useRef 建立出一個物件實體,null 表示初始值設定為 null,將建立好的物件丟入要抓取的 DOM 元素的 ref attribute 中,之後透過 inputRef.current 取得 input 的 DOM 物件

const component = () => {
const inputRef = useRef(null);

useEffect(() => {
inputRef.current.focus();
}, []);

return <input ref={inputRef} type="text" placeholder="Enter text" />;
};

倘若希望在 ref 掛載完成後執行某些事情,則可以使用 callback ref

function MeasureExample() {
const [height, setHeight] = useState(0);

const measuredRef = useCallback((node) => {
if (node !== null) {
//getBoundingClientRect 用於取得元素相對於視窗的座標位置
setHeight(node.getBoundingClientRect().height);
}
}, []);

return (
<>
<h1 ref={measuredRef}>Hello, world</h1>
<h2>The above header is {Math.round(height)}px tall</h2>
</>
);
}

其他類似操作:滾動圖片到視圖、播放和暫停影片

forwardRef: 讓父層取得子層 DOM 元素

//父層建立 ref
- 先在父層元件透過 useRef 創建一個 ref並傳至子元件
const App = () => {
const inputRef = React.useRef(null);

// 父層可以操作子層 input 元素的 focus
React.useEffect(() => {
console.log(inputRef.current); // <input type="text">...</input>
inputRef.current.focus(); // 對 AwesomeInput 中的 <input /> 進行操作
}, []);

return <AwesomeInput ref={inputRef} />;
};

//子層使用 forwardRef
- 子元件透過 forwardRef將input傳出去
const AwesomeInput = React.forwardRef(({ value, change }, ref) => {
return <input type="text" value={value} onChange={onChange} ref={ref} />;
});

參考資料