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>
);
};
常見用法
- 紀錄元件資料狀態,不受渲染影響(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>
);
- 透過 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} />;
});