一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第21天,点击查看活动详情。
useRef 返回一个可变的ref对象,该对象只有一个current属性,该对象在组件的整个生命周期内保持不变,每次重新渲染后都不会重新初始化值,和useState一样,不同的是修改后不会重新渲染组件re-render。
使用
语法类型定义
// 语法类型定义
interface MutableRefObject<T> {
current: T;
}
function useRef<T>(initialValue: T): MutableRefObject<T>;
useRef函数接收一个任类型的参数作为初始化值initialValue,返回一个对象,对象中只有一个属性current,首次渲染时会将initialValue值赋给current属性,该对象是一个被冻结对象,不能添加其他属性不能删除current属性。
// 源码部分
var ref = {
current: initialValue
};
{
Object.seal(ref);
}
hook.memoizedState = ref;
因此我们不管是定义基本数据类型还是其他类型,本质上内部其实都是引用类型,React会将该数据存储上,每次重新渲染时其实使用的都是它的引用,所以所有渲染周期中都用的是最新的值,在所有渲染周期都是可变的,但useState定义的数据在不同渲染周期中是相互独立的,那么使用是也是独立的,如下:
const Demo: React.FC = (props) => {
const [count, setCount] = useState<number>(0);
const countRef = useRef(0);
function onClick() {
setCount((prevCount: number) => {
return count + 1;
});
countRef.current = countRef.current + 1;
}
function onTip() {
setTimeout(() => {
alert(`useState:${count};useRef${countRef.current}`);
}, 5000)
}
return (
<React.Fragment>
<div onClick={onClick}>点击:{count}</div>
<div onClick={onTip}>提示</div>
</React.Fragment>
)
}
先点击
提示,下来一直连续点击点击,触发每次重新渲染组件,最后提示useState的值为0,而useRef的值为1。因为每次重新渲染会重新定义useState的count,并赴一个新值,而useRef不会重新定义,我们只是给它重新赋新值,引用没有变, onTip方法每次渲染重新定义,每次用的都是当时定义的变量在内存中的位置指向的值,因为useRef定义的它的内存位置一直没变,只是值变了,而useState定义的基本类型每次定义的内存位置都不一样,所以提示的是调用onTip时的值。
使用场景
根据它的特性在所有render渲染时拿到的都是同一个引用,值都是最新的,我们常用于访问DOM节点,对DOM进行操作,监听事件等。
const Demo: React.FC = (props) => {
const inputRef = useRef<HTMLInputElement>(null);
function onTip() {
alert(inputRef.current?.value);
}
return (
<React.Fragment>
<input ref={inputRef} defaultValue="你好" />
<div onClick={onTip}>提示</div>
</React.Fragment>
)
}