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 对象。在组件的生命周期内,ref 的 current 属性会保持对相应 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 来代替 createRef。useRef 会返回一个带有 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 相似,useRef 的 current 属性在组件的整个生命周期内保持不变,适合需要持续引用 DOM 元素的场景。

createRef 和 useRef 的主要区别

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

使用场景

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

结语✒️

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

相关推荐
moshuying1 小时前
网购能买Token了!
前端
h_65432101 小时前
echarts实现柱状图加一条横线
前端·echarts
风骏时光牛马2 小时前
生成一个后端标题,只需要一个标题,不需要其他的任何文本。
前端
子非鱼@Itfuture2 小时前
关于前后端联调中登录状态/登录信息失效?
java·前端
郭小李2 小时前
openFeign入门
java·开发语言·前端
馒头不想说话2 小时前
AI当运营,帮你省人力
前端
梦曦i2 小时前
uni-app x下自研架构的工程化突围
前端·架构·uni-app x
速易达网络2 小时前
ECharts 图表制作完全指南:从零到可视化实战
前端·javascript·echarts
IT_陈寒2 小时前
SpringBoot多环境配置把我坑惨了,这个踩坑经验你最好看看
前端·人工智能·后端
徐小夕3 小时前
深度剖析 30k star 的编码 Agent DeepSeek-Reasonix:长会话 Token 成本直降 80%
前端·vue.js·github