用好useRef让React组件性能提升的几个实用技巧

玉淇 框架 阅读 809
赞 24 收藏
二维码
手机扫码查看
反馈

先看效果,再看代码

最近在做一个项目的时候,有个需求是要操作DOM元素的焦点。我第一时间想到的就是用useRef,因为这玩意儿真的太好用了。来,直接上代码:

用好useRef让React组件性能提升的几个实用技巧

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的一些总结和实战经验分享。其实它的用法远不止这些,比如还可以用在动画、第三方库集成等场景。这个技术的拓展用法还有很多,后续会继续分享这类博客。

如果你有更优的实现方式,或者发现了新的用法,欢迎评论区交流!希望这篇文章能帮你少踩几个坑,早点下班去摸鱼。

本文章不代表JZTHEME立场,仅为作者个人观点 / 研究心得 / 经验分享,旨在交流探讨,供读者参考。
发表评论

暂无评论