React 中ref的三种形式

引言💭

在 React 中,ref 是一个重要的功能,用于直接访问 DOM 元素或组件实例。通常,我们使用 ref 来实现一些需要直接操作 DOM 的场景,例如焦点管理、文本选择或动画等。

在 React 中,ref 主要有三种形式:字符串形式、回调形式和 createRef

一、字符串形式的 ref(不推荐使用)

ref 可以使用字符串形式来引用 DOM 元素或组件实例,如下所示:

scala 复制代码
class MyComponent extends React.Component {
  render() {
    return <div ref="myDiv">Hello</div>;
  }

  componentDidMount() {
    console.log(this.refs.myDiv);  // 通过 refs 获取 DOM 元素
  }
}

在组件挂载后,React 会在 refs 对象中自动为每个字符串形式的 ref 创建一个属性,指向对应的 DOM 元素或组件实例。

使用场景

  • 字符串形式的 ref 在早期版本中常用于引用 DOM 元素,尤其是对于较简单的组件而言。
  • 然而,其缺乏灵活性,且容易导致潜在的性能问题和调试困难。因此,开发者应避免使用字符串形式的 ref

二、回调形式的 ref

类方法中的回调 ref

在 React 中,回调形式的 ref 是通过将一个函数传递给 ref 属性来动态设置引用的方式。这个函数会在组件挂载时被调用,并将对应的 DOM 元素或组件实例作为参数传递给它。这个方式通常用于需要在组件生命周期的特定时刻访问 DOM 或组件实例的情况。

scala 复制代码
class MyComponent extends React.Component {
  setRef = (element) => {
    this.myDiv = element;  // 获取 DOM 元素
  };

  render() {
    return <div ref={this.setRef}>Hello</div>;
  }

  componentDidMount() {
    console.log(this.myDiv);  // 通过 this.myDiv 获取 DOM 元素
  }
}

在这个例子中,ref={this.setRef}setRef 方法作为回调函数传递。当组件挂载时,React 会调用 setRef 函数,并将 DOM 元素作为参数传入。这样,this.myDiv 就能引用到挂载的 DOM 元素。

内联回调函数

除了使用类方法来定义回调函数,你还可以将回调函数直接写成内联函数,进一步简化代码。这种写法特别适用于一些简单的场景,避免了额外定义方法。

scala 复制代码
class MyComponent extends React.Component {
  render() {
    return <div ref={(element) => { this.myDiv = element; }}>Hello</div>;
  }

  componentDidMount() {
    console.log(this.myDiv);  // 通过 this.myDiv 获取 DOM 元素
  }
}

在这个例子中,ref={(element) => { this.myDiv = element; }} 就是一个内联的回调函数。每当 DOM 元素挂载时,React 会调用该回调,并将 DOM 元素作为参数传入。内联函数写法使得代码更加简洁,适合不需要在其他地方使用 ref 的情况。

使用场景

  • 动态引用 DOM 元素 :如果你需要动态访问不同的 DOM 元素(例如多个同类型的元素),回调形式的 ref 非常有用。每当元素挂载或卸载时,回调函数会被自动调用,从而让你能够及时访问或清理引用。
  • 条件渲染 :在某些条件下渲染不同的 DOM 元素,并需要访问它们时,回调形式的 ref 可以确保你在元素实际挂载后才获得对它的引用。

三、createRef(推荐)

createRef 是 React 16.3 引入的一个新 API,是现代 React 中推荐使用的 ref 创建方式。与回调函数形式不同,createRef 提供了一种更加可靠和清晰的方式来引用 DOM 元素或组件实例,并且与每个组件实例绑定,确保 ref 在组件的生命周期内保持一致。

为什么推荐使用 createRef

createRef 创建的 ref专人专用的 ,每个组件实例都会拥有一个独立的 ref 对象。在组件的生命周期内,refcurrent 属性会保持对相应 DOM 元素的引用,且不会因为重新渲染而发生变化,这使得它比回调形式的 ref 更加稳定和高效。

在类组件中的使用

scala 复制代码
class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.myDivRef = React.createRef();  // 使用 createRef 创建 ref
  }

  componentDidMount() {
    console.log(this.myDivRef.current);  // 通过 current 获取 DOM 元素
  }

  render() {
    return <div ref={this.myDivRef}>Hello</div>;
  }
}

在这段代码中,我们通过 React.createRef() 创建了一个 ref,并将其赋值给 this.myDivRef。每个组件实例都会拥有一个独立的 myDivRef。当组件挂载时,this.myDivRef.current 会指向 DOM 元素,且在组件的生命周期内不会变化,保证了 ref 的一致性。

在函数组件中的使用

对于函数组件,createRef 并不常用。函数组件通常使用 useRef 来代替 createRefuseRef 会返回一个带有 current 属性的对象,类似于 createRef,但它在函数组件中更为常见,并且会在组件的整个生命周期内保持不变。

javascript 复制代码
import React, { useRef, useEffect } from 'react';

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

  useEffect(() => {
    console.log(myDivRef.current);  // 通过 current 获取 DOM 元素
  }, []);  // 仅在挂载时调用

  return <div ref={myDivRef}>Hello</div>;
}

在这个例子中,useRef 创建了一个 ref,并将其传递给 div 元素。myDivRef.current 会指向该 DOM 元素。与 createRef 相似,useRefcurrent 属性在组件的整个生命周期内保持不变,适合需要持续引用 DOM 元素的场景。

createRefuseRef 的主要区别

  • 类组件中使用 createRefcreateRef 在类组件中使用时,每个组件实例都会有一个独立的 ref 对象,它是专人专用的,且在组件生命周期内保持一致,不会因重新渲染而变化。
  • 函数组件中使用 useRef :在函数组件中,useRef 是代替 createRef 的常用方式,提供了与 createRef 类似的功能,且它的引用对象在整个生命周期内保持稳定,避免了回调形式 ref 的频繁创建。

使用场景

  • 类组件中的引用 :对于类组件,createRef 是管理 ref 的推荐方式,它保证了每个组件实例拥有独立的、稳定的引用。
  • 函数组件中的引用 :在函数组件中,useRef 是创建 ref 的标准方式,它提供了与 createRef 类似的功能,适合需要持久引用的场景。

结语✒️

持续更新中......🚀🚀🚀

相关推荐
LAOLONG-C7 分钟前
今日CSS学习浮动->定位
前端·css·css3
城南旧事14 分钟前
SSE (Server-Send Events) 服务端实时推送技术
前端
Mapmost19 分钟前
【数据可视化艺术·应用篇】三维管线分析如何重构城市"生命线"管理?
前端·数据可视化
palpitation971 小时前
在Flutter中使用Builder的正确方式:一场context的教育
前端
Eliauk__1 小时前
深入剖析 Vue 双向数据绑定机制 —— 从响应式原理到 v-model 实现全解析
前端·javascript·面试
代码小学僧1 小时前
Cursor 的系统级提示词被大佬逆向出来了!一起来看看优秀 prompt是怎么写的
前端·ai编程·cursor
MrsBaek1 小时前
前端笔记-Axios
前端·笔记
洋流1 小时前
什么?还没弄懂关键字this?一篇文章带你速通
前端·javascript
晴殇i1 小时前
for...in 循环的坑,别再用它遍历 JavaScript 数组了!
前端·javascript
littleplayer1 小时前
iOS 单元测试详细讲解-DeepSeek
前端