總覽
當我們在一個函式元件中使用一個字串作為ref
時,會產生"Function components cannot have string refs"錯誤。為了解決該錯誤,使用useRef()
鉤子來得到一個可變的ref
物件,這樣你就可以在元件中作為ref
使用。
這裡有個示例用來展示錯誤是如何發生的。
// App.js
export default function App() {
// A string ref has been found within a strict mode tree.
// ⛔️ Function components cannot have string refs.
// We recommend using useRef() instead.
return (
<div>
<input type="text" id="message" ref="msg" />
</div>
);
}
上述程式碼片段的問題在於,我們使用了字串作為ref
。
useRef
為了解決該錯誤,使用useRef
鉤子來獲取可變的ref
物件。
// App.js
import {useEffect, useRef} from 'react';
export default function App() {
const refContainer = useRef(null);
useEffect(() => {
// ?️ this is reference to input element
console.log(refContainer.current);
refContainer.current.focus();
}, []);
return (
<div>
<input type="text" id="message" ref={refContainer} />
</div>
);
}
useRef()
鉤子可以被傳遞一個初始值作為引數。該鉤子返回一個可變的ref
物件,其.current
屬性被初始化為傳遞的引數。
需要注意的是,我們必須訪問ref
物件上的current
屬性,以獲得對我們設定了ref
屬性的input
元素的訪問。
當我們傳遞ref
屬性到元素上時,比如說,<input ref={myRef} />
。React將ref
物件上的.current
屬性設定為相應的DOM節點。
useRef
鉤子建立了一個普通的JavaScript物件,但在每次渲染時都給你相同的ref
物件。換句話說,它幾乎是一個帶有.current
屬性的記憶化物件值。
不會重新渲染
應該注意的是,當你改變ref
的current
屬性的值時,不會引起重新渲染。
例如,一個ref
不需要包含在useEffect
鉤子的依賴陣列中,因為改變它的current
屬性不會引起重新渲染。
// App.js
import {useEffect, useRef} from 'react';
export default function App() {
const refContainer = useRef(null);
const refCounter = useRef(0);
useEffect(() => {
// ?️ this is reference to input element
console.log(refContainer.current);
refContainer.current.focus();
// ?️ incrementing ref value does not cause re-render
refCounter.current += 1;
console.log(refCounter.current);
}, []);
return (
<div>
<input type="text" id="message" ref={refContainer} />
</div>
);
}
例子中的useEffect
鉤子只執行了2次,因為useRef
在其內容發生變化時並沒有通知我們。
改變物件的current
屬性並不會導致重新渲染。