理解 React 中的 useRef(不再困惑)

发布: (2026年1月9日 GMT+8 00:48)
6 min read
原文: Dev.to

Source: Dev.to

Understanding useRef in React

如果你一直在学习 React,可能已经熟练掌握了 useStateuseEffect。但随后你会遇到 useRef,这时感觉…有点怪异。

它不会更新屏幕,也不会触发重新渲染。它好像违背了“React 规则”。其实秘密在于,useRef 是你组件的私有、持久化存储。

下面我们来拆解它到底做了什么、为什么有用,以及如何在不头疼的情况下使用它。

useRef 实际是什么

从本质上讲,useRef 为你提供了一个存放值的地方,该值:

  • 在渲染之间保持不变
  • 可以随时更改
  • 更改时不会导致重新渲染
const myRef = useRef(initialValue);

React 会给你一个看起来像这样的对象:

{ current: initialValue }

关键在于 .current。值就存放在那里。React 只会创建一次这个对象,并在每次渲染时返回同一个对象。

为什么 useRef 会存在

你可能会想:“为什么不直接用 useState 来处理所有事情?” 区别在于可见性。

  • State 用于你希望用户看到的东西(UI)。当状态改变时,React 会重新绘制屏幕。
  • Refs 用于你想在幕后记住的东西。当 ref 改变时,React 保持沉默,不会对 UI 做任何操作。

典型的 ref 使用场景:

  • 一个 DOM 元素
  • 一个定时器 ID
  • 一个 WebSocket 连接
  • 一个先前的值
  • 一个标记或计数器

把这些放进 state 会导致不必要的重新渲染。使用普通变量又会在每次渲染时被重置。useRef 正是为了解决这个问题,它提供了记忆功能而不会触发渲染。

最常见的用法:访问 DOM

这是大多数人第一次接触 useRef 的地方。

import { useRef } from "react";

function MyComponent() {
  const inputRef = useRef(null);

  return (
    <>
      
       inputRef.current.focus()}>
        Focus
      
    
  );
}

React 会把真实的 DOM 输入元素放入 inputRef.current,从而让你可以直接调用诸如 focus() 之类的方法。这是正确的做法,用于:

  • 聚焦输入框
  • 将元素滚动到可视区域
  • 测量宽度或高度
  • 控制视频或音频元素

DOM 节点不应该放在 state 中;ref 才是合适的工具。

在渲染之间保持值(不触发重新渲染)

有时你需要记住某些东西,但不想让 React 介入。例如:统计组件渲染了多少次。

const renderCount = useRef(0);
renderCount.current += 1;

这个值:

  • 在每次渲染时增加
  • 永不导致重新渲染
  • 永不重置

可用于计数器、标记、缓存数据或内部账务处理。

跟踪先前的值

React 默认不会提供“先前的状态”。useRef 填补了这个空白。

function MyComponent({ value }) {
  const prevValue = useRef(value);

  useEffect(() => {
    prevValue.current = value;
  }, [value]);

  // now prevValue.current holds the previous `value`
}

value 是当前值,而 prevValue.current 是先前的值。这个模式简洁、可预测且被广泛使用。

存储外部对象

有些东西根本不属于 React:

  • WebSocket 连接
  • AbortController 实例
  • 观察者
  • 第三方库对象
function useWebSocket(url) {
  const socketRef = useRef(null);

  useEffect(() => {
    socketRef.current = new WebSocket(url);
    return () => socketRef.current.close();
  }, [url]);

  return socketRef.current;
}

这些对象需要一个稳定的存放位置;useRef 提供了它。把它们放入 state 是设计错误。

useRef 不是

  • 不是 useState 的替代品。
  • 不是 响应式的,不应用于更新 UI。

如果 UI 依赖于某个值,请使用 state。如果 React 不需要了解它,请使用 ref。遵循此规则可以避免大多数错误。

简单的思维模型

useRef 想象成附着在组件上的一个小盒子:

  • React 渲染组件。
  • 盒子在多次渲染之间保持不变。
  • 你可以把任何东西放进盒子里(.current)。
  • React 完全忽略这个盒子。

就是这么回事。

最后思考

useRef 并不复杂——它很直接。它为你提供了一个存放 React 不该管理的东西的地方。只要你明白了这一点,它就不再显得“高级”,而是显而易见。当你真正领悟到它的用法时,你的组件将会:

  • 更简洁
  • 更可预测
  • 更易于理解

这不是魔法——这是为合适的工作使用合适的工具。

Back to Blog

相关文章

阅读更多 »