创见博客
React之uesRef
七崽爱吃小饼干2026/01/08阅读 0专栏 React

一、useRef 是什么?

useRef 是 React 提供的一个内置钩子(Hook),核心作用是创建一个可以在组件整个生命周期内持久化的可变容器(ref 对象)。

这个容器有一个唯一的属性 .current,你可以把任意类型的值(比如 DOM 元素、普通变量、对象等)存到 .current 里,且:

  1. 修改 .current 的值不会触发组件重新渲染;
  2. 组件重新渲染时,useRef 返回的 ref 对象始终是同一个(不会重新创建);
  3. 这个值会在组件挂载、更新、卸载的整个生命周期中保留,不会像普通变量一样在每次渲染时重置。

基础用法示例:

jsx
import { useRef } from 'react';

function MyComponent() {
  // 创建一个 ref 对象,初始值为 0
  const countRef = useRef(0);

  const handleClick = () => {
    // 修改 .current 不会触发组件重渲染
    countRef.current += 1;
    console.log('点击次数:', countRef.current); // 能正确打印,但页面不会更新
  };

  return (
    <button onClick={handleClick}>
      点击(控制台看次数)
    </button>
  );
}

二、useRef vs useState 核心区别

这是新手最容易混淆的点,核心差异在于是否触发重渲染和值的更新逻辑,具体对比如下:

特性useRefuseState
触发重渲染修改 .current 不会触发重渲染调用 setState 会触发组件重渲染
值的持久性生命周期内始终是同一个 ref 对象状态值持久化,但每次 setState 会生成新值
取值/改值方式直接读写 .current(无限制)读:直接取状态变量;改:必须通过 setState
适用场景存储无需渲染的可变值、获取DOM存储需要驱动视图更新的状态

对比示例:

jsx
import { useRef, useState } from 'react';

function CompareDemo() {
  const [countState, setCountState] = useState(0);
  const countRef = useRef(0);

  // 点击更新 useState:页面会刷新
  const handleStateClick = () => {
    setCountState(prev => prev + 1);
  };

  // 点击更新 useRef:页面不刷新,仅控制台打印
  const handleRefClick = () => {
    countRef.current += 1;
    console.log('ref 计数:', countRef.current);
  };

  return (
    <div>
      <p>useState 计数:{countState}</p>
      <button onClick={handleStateClick}>更新 useState</button>
      <button onClick={handleRefClick}>更新 useRef</button>
    </div>
  );
}

三、useRef 的主要用途

1. 获取/操作 DOM 元素(最常用)

通过 ref 属性绑定 DOM 元素,就能在组件中直接访问并操作该 DOM(比如聚焦输入框、获取元素尺寸等)。

jsx
import { useRef, useEffect } from 'react';

function InputFocus() {
  // 创建 ref 绑定到 input 元素
  const inputRef = useRef(null);

  useEffect(() => {
    // 组件挂载后,让 input 自动聚焦
    inputRef.current.focus();
  }, []);

  return (
    <input 
      ref={inputRef} 
      type="text" 
      placeholder="自动聚焦的输入框" 
    />
  );
}

2. 存储无需触发渲染的可变值

比如记录组件渲染次数、定时器 ID、上一次的状态值等,这些值不需要展示在页面上,修改后也不需要触发重渲染。

jsx
import { useRef, useEffect, useState } from 'react';

function RenderCounter() {
  const [count, setCount] = useState(0);
  // 存储渲染次数(无需驱动视图)
  const renderCountRef = useRef(0);
  // 存储上一次的 count 值
  const prevCountRef = useRef(0);

  useEffect(() => {
    // 每次渲染后,更新渲染次数
    renderCountRef.current += 1;
    // 每次 count 变化后,更新上一次的值
    prevCountRef.current = count;
  });

  return (
    <div>
      <p>当前 count:{count}</p>
      <p>上一次 count:{prevCountRef.current}</p>
      <p>组件渲染次数:{renderCountRef.current}</p>
      <button onClick={() => setCount(prev => prev + 1)}>加 1</button>
    </div>
  );
}

3. 保存定时器/订阅等清理逻辑的引用

组件卸载时需要清理定时器、取消订阅,用 useRef 存储定时器 ID,能在任意时机访问到这个 ID。

jsx
import { useRef, useEffect, useState } from 'react';

function TimerDemo() {
  const [time, setTime] = useState(0);
  // 存储定时器 ID
  const timerRef = useRef(null);

  useEffect(() => {
    // 启动定时器
    timerRef.current = setInterval(() => {
      setTime(prev => prev + 1);
    }, 1000);

    // 组件卸载时清理定时器
    return () => {
      clearInterval(timerRef.current);
    };
  }, []);

  return (
    <div>
      <p>计时:{time} 秒</p>
      <button onClick={() => clearInterval(timerRef.current)}>暂停</button>
    </div>
  );
}

总结

  1. useRef 是创建生命周期内持久化的可变容器,修改 .current 不触发重渲染;useState 用于存储驱动视图更新的状态,修改会触发重渲染。
  2. useRef 核心用途:① 获取/操作 DOM 元素;② 存储无需渲染的可变值(如渲染次数、定时器 ID);③ 保存上一次的状态/值。
  3. 选择原则:需要更新后刷新页面 → 用 useState;仅需持久化存储、无需刷新页面 → 用 useRef。
评论
0/100