用好useRef让React组件性能提升的几个实用技巧
先看效果,再看代码
最近在做一个项目的时候,有个需求是要操作DOM元素的焦点。我第一时间想到的就是用useRef,因为这玩意儿真的太好用了。来,直接上代码:
import React, { useRef } from 'react';
function FocusInput() {
const inputRef = useRef(null);
const handleFocus = () => {
inputRef.current.focus();
};
return (
<div>
<input ref={inputRef} type="text" />
<button onClick={handleFocus}>聚焦输入框</button>
</div>
);
}
export default FocusInput;
这段代码的效果很简单:点击按钮后,输入框会自动获得焦点。亲测有效,简单粗暴。
不只是DOM引用,还能存值
刚开始学React的时候,我以为useRef只能用来操作DOM,后来才发现它还有个隐藏技能——可以存值!而且这个值不会触发组件重新渲染。举个例子:
import React, { useRef, useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
const prevCountRef = useRef();
function handleClick() {
prevCountRef.current = count; // 存储当前值
setCount(count + 1);
}
return (
<div>
<p>当前值: {count}, 上一个值: {prevCountRef.current}</p>
<button onClick={handleClick}>增加</button>
</div>
);
}
export default Counter;
这里的核心是prevCountRef.current,它可以在组件更新时保存之前的值。注意,这种方式不会触发重新渲染,非常适合用来存储一些不需要触发UI更新的状态。
踩坑提醒:这三点一定注意
虽然useRef很好用,但我还是踩了不少坑,分享一下:
- 1. 别忘了初始化:如果你用
useRef来存值,一定要记得给它初始化值。比如:const myRef = useRef(initialValue)。不然myRef.current默认是undefined,可能会导致意外错误。 - 2. 别乱改DOM:虽然
useRef可以直接操作DOM,但尽量别滥用。React的设计理念是声明式编程,如果到处直接操作DOM,很容易导致代码难以维护。 - 3. 注意生命周期问题:在某些情况下,比如组件卸载后,你可能还会尝试访问
ref.current。这种时候就容易报错,所以要确保你的逻辑在正确的生命周期内运行。
高级技巧:和定时器结合使用
有时候我们需要在组件中设置定时器,但如果直接用普通的变量存储定时器ID,可能会遇到问题,因为组件重新渲染会导致变量丢失。useRef就派上用场了:
import React, { useRef } from 'react';
function Timer() {
const timerRef = useRef(null);
const startTimer = () => {
if (timerRef.current) return; // 防止重复启动
timerRef.current = setInterval(() => {
console.log('每秒执行一次');
}, 1000);
};
const stopTimer = () => {
if (timerRef.current) {
clearInterval(timerRef.current);
timerRef.current = null;
}
};
return (
<div>
<button onClick={startTimer}>开始定时器</button>
<button onClick={stopTimer}>停止定时器</button>
</div>
);
}
export default Timer;
这个例子中,我们用useRef来存储定时器的ID,这样即使组件重新渲染,定时器ID也不会丢失。建议直接用这种方式,比普通变量靠谱多了。
这个场景最好用
除了上面提到的几种用法,useRef还有一个特别适合的场景:在表单中操作文件上传。假设我们要实现一个文件上传功能,并且需要在用户选择文件后立即获取文件内容,可以用useRef轻松搞定:
import React, { useRef } from 'react';
function FileUploader() {
const fileInputRef = useRef(null);
const handleFileChange = () => {
const files = fileInputRef.current.files;
if (files.length > 0) {
console.log('选中的文件:', files[0]);
}
};
return (
<div>
<input type="file" ref={fileInputRef} onChange={handleFileChange} />
</div>
);
}
export default FileUploader;
这里的关键是通过ref直接访问原生DOM的files属性,非常方便。这个场景下,useRef几乎是最佳选择。
拓展用法还有很多
以上是我对useRef的一些总结和实战经验分享。其实它的用法远不止这些,比如还可以用在动画、第三方库集成等场景。这个技术的拓展用法还有很多,后续会继续分享这类博客。
如果你有更优的实现方式,或者发现了新的用法,欢迎评论区交流!希望这篇文章能帮你少踩几个坑,早点下班去摸鱼。

暂无评论