博主头像
<CodeEra />

心存敬畏 行有所止

React Hooks 系列:useRef 的解析笔记

useRef 用法详解

useRef 是 React 中的一个 Hook,用于在函数组件中创建和访问可变的引用对象。它的主要用途包括:

  1. 访问 DOM 元素:通过 useRef 可以直接访问 DOM 节点。
  2. 存储可变值useRef 可以用来存储任何可变值,且在组件重新渲染时不会丢失。

基本用法

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

function MyComponent() {
  // 创建一个 ref 对象
  const myRef = useRef(null);

  useEffect(() => {
    // 访问 DOM 元素
    if (myRef.current) {
      myRef.current.focus();
    }
  }, []);

  return (
    <div>
      {/* 将 ref 绑定到 DOM 元素 */}
      <input ref={myRef} type="text" />
    </div>
  );
}

详细说明

1. 创建 ref 对象

  • 使用 useRef(initialValue) 创建一个 ref 对象。
  • initialValue 是 ref 对象的初始值,通常为 null

2. 访问 ref 对象

  • 通过 myRef.current 访问 ref 对象的当前值。
  • 对于 DOM 元素,myRef.current 指向该 DOM 节点。

3. 更新 ref 对象

  • 通过 myRef.current = newValue 更新 ref 对象。
  • 更新 ref 对象不会触发组件重新渲染。

使用场景

1. 访问 DOM 元素

  • 常用于表单输入、焦点管理、动画等场景。
function TextInputWithFocusButton() {
  const inputEl = useRef(null);

  const onButtonClick = () => {
    // 点击按钮时聚焦输入框
    inputEl.current.focus();
  };

  return (
    <>
      <input ref={inputEl} type="text" />
      <button onClick={onButtonClick}>Focus the input</button>
    </>
  );
}

2. 存储可变值

  • 用于存储计时器 ID、上一次的 props 或 state 等。
function Timer() {
  const timerId = useRef(null);

  const startTimer = () => {
    timerId.current = setInterval(() => {
      console.log('Timer tick');
    }, 1000);
  };

  const stopTimer = () => {
    clearInterval(timerId.current);
  };

  return (
    <div>
      <button onClick={startTimer}>Start Timer</button>
      <button onClick={stopTimer}>Stop Timer</button>
    </div>
  );
}

注意事项

  • 不会触发重新渲染:更新 useRef 的值不会导致组件重新渲染。
  • 初始值useRef 的初始值只在组件挂载时设置一次,后续渲染时不会重新初始化。
  • 避免滥用:虽然 useRef 可以存储任意值,但应谨慎使用,避免破坏 React 的数据流。

useRefcreateRef 的区别

useRefcreateRef 都是 React 中用于创建引用(ref)的工具,但它们在用法、行为和应用场景上有一些关键区别。

1. useRef

  • 使用场景:用于函数组件。
  • 特点

    • 在函数组件的整个生命周期中,useRef 返回的 ref 对象是持久化的,即使组件重新渲染,useRef 的值也不会丢失。
    • 适合存储可变值(如 DOM 引用、计时器 ID 等),且不会触发组件重新渲染。
    • 每次渲染时,useRef 返回的是同一个 ref 对象。

2. createRef

  • 使用场景:通常用于类组件。
  • 特点

    • 每次组件渲染时,createRef 都会创建一个新的 ref 对象
    • 如果用于函数组件,每次渲染都会生成一个新的 ref,导致 ref 的值丢失。
    • 适合类组件中需要动态创建 ref 的场景。

3. 主要区别

特性useRefcreateRef
适用组件类型函数组件类组件
生命周期持久化,组件重新渲染时不会丢失每次渲染都会创建新的 ref 对象
性能更高效,适合频繁更新的场景每次渲染都会创建新的对象,性能稍差
使用场景函数组件中访问 DOM 或存储可变值类组件中访问 DOM 或动态创建 ref

为什么函数组件中推荐使用 useRef

  • 在函数组件中,每次渲染都会重新执行函数体。如果使用 createRef,每次渲染都会创建一个新的 ref 对象,导致 ref 的值丢失。
  • useRef 在函数组件的整个生命周期中会返回同一个 ref 对象,确保 ref 的值在重新渲染时不会丢失。

错误示例(函数组件中使用 createRef

function MyComponent() {
  const myRef = createRef(); // 每次渲染都会创建新的 ref

  useEffect(() => {
    console.log(myRef.current); // 可能为 null,因为每次渲染都会重新创建 ref
  }, []);

  return <div ref={myRef}>Hello, createRef!</div>;
}

正确示例(函数组件中使用 useRef

function MyComponent() {
  const myRef = useRef(null); // 持久化的 ref

  useEffect(() => {
    console.log(myRef.current); // 正常访问 DOM 元素
  }, []);

  return <div ref={myRef}>Hello, useRef!</div>;
}

总结

  • useRef:用于函数组件,持久化 ref 对象,适合存储可变值或访问 DOM 元素。
  • createRef:用于类组件,每次渲染都会创建新的 ref 对象,适合类组件中的动态 ref 需求。

在函数组件中,优先使用 useRef,而在类组件中,使用 createRef 是更合适的选择。理解它们的区别和适用场景,可以帮助你更好地管理 React 组件中的状态和副作用。

发表新评论