useRef 是 React 中非常常用的 Hook,核心特点:
在组件多次渲染之间保存一个可变值,并且修改它不会触发重新渲染。
主要有三个用途:获取 DOM、保存可变数据、和 createRef 的区别。
1. 获取 DOM 元素(最常见)
类似 Vue 的 ref。
例子:获取 input 并自动聚焦
import { useRef, useEffect } from "react";
function App() {
const inputRef = useRef(null);
useEffect(() => {
inputRef.current.focus();
}, []);
return (
<input ref={inputRef} />
);
}
执行流程:
首次渲染
↓
inputRef = { current: null }
DOM挂载完成
↓
React自动赋值
inputRef.current = input节点
useEffect执行
↓
focus()
此时:
inputRef.current
得到:
<input>
常见用途:
获取元素高度
获取滚动位置
focus()
播放视频
canvas操作
上传文件
例如:
divRef.current.scrollIntoView();
videoRef.current.play();
2. 保存可变数据(不会触发重新渲染)
这是很多人忽略但很重要的用途。
假设统计点击次数:
用 state
const [count, setCount] = useState(0);
修改:
setCount(count + 1);
会重新渲染。
用 ref
const countRef = useRef(0);
function add() {
countRef.current++;
console.log(countRef.current);
}
修改:
countRef.current++;
不会重新 render。
适合保存:
定时器ID
上一次值
缓存数据
防抖timer
socket实例
请求状态
例:
保存 setTimeout:
const timerRef = useRef(null);
useEffect(() => {
timerRef.current = setTimeout(() => {
console.log("执行");
},1000);
return () => {
clearTimeout(timerRef.current);
}
},[])
避免:
组件销毁
timer丢失
内存泄漏
3. 获取上一次值(经典面试题)
记录前一个 state:
function App() {
const [count,setCount]=useState(0);
const prevRef=useRef();
useEffect(()=>{
prevRef.current=count;
},[count])
return (
<>
当前:{count}
上次:{prevRef.current}
</>
)
}
效果:
当前:3
上次:2
因为:
render
↓
useEffect
↓
更新 ref
4. useRef 与 createRef 区别(面试高频)
createRef
class App extends React.Component {
inputRef = React.createRef();
}
主要给 类组件 用。
函数组件里:
const ref = createRef();
问题:
每次 render 都会重新创建:
render1
ref = {}
render2
ref = {}
不是同一个对象。
useRef
const ref = useRef();
只创建一次:
render1
ref={current:null}
render2
还是同一个ref
不会变。
所以函数组件推荐:
函数组件 → useRef
类组件 → createRef
对比表:
| 区别 | useRef | createRef |
|---|---|---|
| 适用 | 函数组件 | 类组件 |
| 是否重新创建 | 否 | 是 |
| 保存值 | 可以 | 不适合 |
| 获取DOM | 支持 | 支持 |
| 触发渲染 | 不触发 | 不触发 |
总结一句:
useRef =
获取DOM
+ 保存跨渲染可变值
+ 不触发更新
+ 函数组件替代 createRef
前端面试里经常问:
useRef 为什么修改 current 不会触发更新?
因为 React 不会追踪 ref.current 的变化,它只是普通对象:
{
current: xxx
}
修改对象属性,不会进入 React 的状态更新流程。