React Refs

大多数场景下数据自上而下流动、界面由 state 驱动。但偶尔需要「命令式」地操作一下 DOM——聚焦输入框、测量元素宽高、控制视频播放,或者保存定时器 id 这类与渲染无关的值。Refs 就是 React 为这类需求留出的后门,本节讲清它的用法与边界。

为什么用 Ref 而不是 state

state 与 ref 都能「记住」数据,关键区别在于:state 一变就重新渲染组件,而修改 ref 不会触发渲染。像 DOM 节点、定时器句柄这类数据放进 state,只会带来无谓的渲染。

对比stateref
更新方式setState 函数直接改 ref.current
是否触发渲染
典型用途需要展示的数据DOM 节点、句柄等

useRef 与 ref 属性

函数组件中用 useRef(null) 创建 ref,把它传给元素的 ref 属性,之后 ref.current 就指向真实的 DOM 节点。

import { useRef } from 'react';

export default function FocusDemo() {
  const inputRef = useRef(null);

  function handleFocus() {
    inputRef.current.focus(); // 直接调用 DOM 方法
  }

  return (
    <>
      <input ref={inputRef} placeholder="点按钮聚焦这里" />
      <button onClick={handleFocus}>聚焦输入框</button>
    </>
  );
}

不受控组件:用 ref 读值

不设 value、不监听 onChange,输入框内容交给浏览器维护,需要时再用 ref 读取,这就是「不受控组件」,适合简单、无需校验的表单。

function Uncontrolled() {
  const nameRef = useRef(null);

  function submit() {
    console.log('输入的值:', nameRef.current.value);
    // 输出:输入的值:张三
  }

  return (
    <>
      <input ref={nameRef} defaultValue="张三" />
      <button onClick={submit}>读取输入</button>
    </>
  );
}

ref 保存跨渲染的值

计数器用 ref 保存时,累加不会触发界面刷新,适合记录「只需要记、不需要显示」的数据。

function ClickLog() {
  const times = useRef(0);

  function click() {
    times.current += 1; // 只改内存,不触发渲染
    console.log('共点击', times.current, '次');
    // 输出:共点击 1 次(每点一次数字加一)
  }

  return <button onClick={click}>记录点击</button>;
}

补充:React 16.3 之前的类组件用 React.createRef(),函数组件统一用 useRef,思想相同。ref 内容变化不会通知视图,所以「要展示的内容」不要放进 ref。

小结

Refs 提供一条绕开 state 的通道:用 ref 属性拿到 DOM 节点做聚焦、测量等操作,或用 useRef 保存不触发渲染的临时数据。判断标准很简单——界面需要跟着变就用 state,不需要就考虑 ref。

笔记加载中…