跳到主要内容

useRef

1.是什么

useRef 是 React 中一个能存储值的 Hook,是你在 React 函数组件中存"稳定的值或 DOM 引用"的秘密武器,不会因渲染而丢失,非常适合存 DOM、定时器、最新状态等"静态但重要"的信息。

提示

useRef 本质上是:"一个在组件多次渲染之间始终保持不变的对象"。useRef 不会因为组件重新渲染而改变。(这是真正需要重视的)

2.使用方法

myRef.current 就是你要用的"那个值"。它不会引起页面重新渲染(不像 useState)。

const myRef = useRef(初始值);

3.高频应用场景

3.1 获取 DOM

import { useRef, useEffect } from "react";

function App() {
const inputRef = useRef();

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

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

3.2 保存定时器 ID

function App() {
const timerRef = useRef();

const start = () => {
timerRef.current = setInterval(() => {
console.log("running");
}, 1000);
};

const stop = () => {
clearInterval(timerRef.current);
};

return (
<>
<button onClick={start}>start</button>
<button onClick={stop}>stop</button>
</>
);
}

3.3 保存上一次值

import { useEffect, useRef } from "react";

function App() {
const [count, setCount] = useState(0);
const prevRef = useRef();

useEffect(() => {
prevRef.current = count;
}, [count]);

return (
<div>
<h2>当前:{count}</h2>
<h2>上一次:{prevRef.current}</h2>
<button onClick={() => setCount(count + 1)}>+1</button>
</div>
);
}

3.4 避免重复 render(性能优化)

因为不需要每次移动都 render,所以使用 useRefuseState 性能更好。

const mouseRef = useRef({ x: 0, y: 0 });

window.addEventListener("mousemove", (e) => {
mouseRef.current = { x: e.clientX, y: e.clientY };
});

3.5 结合 forwardRef,useImperativeHandle 实现父组件访问子组件内部 DOM 或方法

不推荐父组件调用子组件的方法,推荐子组件通过 props 控制。更需要关注的是父组件的 state。只有在极端情况下才使用:1. 输入框 focus。2. 滚动控制。3. 动画控制。4. 第三方库:echarts,video,canvas。5. 表单库:reset(),validate(),submit()。

const MyInput = forwardRef((props, ref) => {
const inputRef = useRef<HTMLInputElement>(null);
useImperativeHandle(ref, () => ({
focus: () => inputRef.current?.focus(),
}));
return <input ref={inputRef} />;
});

const Parent = () => {
const inputRef = useRef<HTMLInputElement>(null);
return (
<>
<MyInput ref={inputRef} />
<button onClick={() => inputRef.current?.focus()}>聚焦输入框</button>
</>
);
};