React 组件的3大属性: refs

一、理解

Refs(引用)是 React 中用于访问组件中的 DOM 元素或其他 React 组件实例的一种机制。它们提供了一种途径,使你可以在React中直接操作和访问DOM元素,或者在React组件之间进行通信。

用途:

  • 焦点的管理、文本的选择、媒体的播放;
  • 强制触发动画;
  • 继承三方 DOM 库;

二、创建refs的方式有哪些

2.1、字符串 Refs(不建议使用)

字符串 Refs 是 React 中的一种创建 Refs 的方式,但自 React 16.3 版本开始,官方不再推荐使用它,因为它存在一些潜在的问题,比如性能问题和可维护性问题。然而,为了完整性,我将展示如何使用字符串 Refs,但请谨慎使用它们。

在字符串 Refs 中,你可以将 Ref 分配为一个字符串,通常是在 componentDidMount 中进行分配,然后你可以通过访问 this.refs 来获取引用。

以下是一个示例:

import React, {
    
     Component } from 'react';

class MyComponent extends Component {
    
    
  componentDidMount() {
    
    
    // 分配Ref为字符串
    this.refs.myRefElement.focus();
  }

  render() {
    
    
    return (
      <div>
        <input ref="myRefElement" /> {
    
    /* 分配Ref为字符串 */}
      </div>
    );
  }
}

export default MyComponent;

在上面的示例中,我们使用字符串 "myRefElement" 分配 Ref 给 input 元素,然后在 componentDidMount 中通过 this.refs.myRefElement 访问该元素并将焦点聚焦到它。

尽管字符串 Refs 在过去是有效的,但它们已不再被官方推荐,因为它们在以下方面存在问题:

  1. 性能问题:字符串 Refs 在React内部需要维护一个额外的映射表,以便通过字符串名字查找Ref。这会导致性能问题,尤其在具有大量Refs的组件中。

  2. 可维护性:使用字符串 Refs 时,很难进行静态分析和检查,因此容易出现拼写错误或无法找到的Refs。

因此,建议在现代React应用程序中使用 React.createRef()useRef 钩子来创建Refs,以提高性能和可维护性。

2.2、回调 Refs

回调 Refs 是一种在 React 组件中创建 Refs 的方式,它可以用于访问 DOM 元素或其他组件实例。这种方式在 React 16.3 之前是主要的 Refs 创建方式,虽然在 React 16.3 之后,官方推荐使用 React.createRef()useRef 钩子来创建 Refs,但回调 Refs 仍然是一种有效的方法。

下面是如何使用回调 Refs 的详细描述:

  1. 创建 Refs:在组件中,首先定义一个变量来保存 Ref 对象,通常在构造函数中初始化为 null

    class MyComponent extends React.Component {
          
          
      constructor(props) {
          
          
        super(props);
        this.myRef = null;
      }
    }
    
  2. 分配 Refs 到元素或组件:在需要引用的 DOM 元素或组件上,使用 ref 属性,将 Ref 变量设置为回调函数。

    setMyRef = (element) => {
          
          
      this.myRef = element;
    }
    
    render() {
          
          
      return (
        <div>
          <input ref={
          
          this.setMyRef} />
        </div>
      );
    }
    

    通过这个回调函数,this.myRef 将会引用与之关联的 DOM 元素或组件实例。

  3. 访问 Refs:在需要访问 Refs 的地方,可以使用 this.myRef 来获取引用的元素或组件。

    componentDidMount() {
          
          
      if (this.myRef) {
          
          
        this.myRef.focus(); // 通过 Ref 聚焦到输入框
      }
    }
    

回调 Refs 的优点是它们在更早的 React 版本中是有效的,并且能够很好地用于访问 DOM 元素或子组件的实例。然而,随着 React 版本的更新,官方更推荐使用 React.createRef()useRef 钩子,因为它们在性能和可维护性方面更有优势。当需要在现代 React 项目中创建 Refs 时,通常更好的选择是使用 React.createRef()(类组件)或 useRef 钩子(函数式组件)。

2.3、React.createRef()(推荐使用)

在 React 16.3 以及之后的版本中,你可以使用内置的 React.createRef() 方法来创建 Refs。这是一种官方推荐的方式。

使用 React.createRef() 方式创建 Refs 很简单。以下是一个具体的示例:

import React from 'react';

class MyComponent extends React.Component {
    
    
  constructor(props) {
    
    
    super(props);
    this.myRef = React.createRef(); // 创建Ref对象
  }

  componentDidMount() {
    
    
    // 在组件渲染后,可以访问DOM元素
    this.myRef.current.focus(); // 聚焦到DOM元素
  }

  render() {
    
    
    return (
      <div>
        <input ref={
    
    this.myRef} /> {
    
    /* 将Ref分配给input元素 */}
        <button onClick={
    
    this.focusInput}>Focus Input</button>
      </div>
    );
  }

  focusInput = () => {
    
    
    // 在事件处理程序中访问Ref
    this.myRef.current.focus();
  };
}

export default MyComponent;

在上面的示例中,我们首先在构造函数中使用 React.createRef() 创建了一个Ref对象,然后在input元素上使用 ref 属性将这个Ref分配给DOM元素。在componentDidMount生命周期方法中,我们使用 this.myRef.current 来访问DOM元素并将焦点聚焦到input上。我们还在一个按钮的点击事件处理程序中使用Ref,再次将焦点聚焦到input上。

这就是使用 React.createRef() 创建和访问Refs的一般过程。这种方式通常用于访问和操作DOM元素,或者引用子组件的实例。

2.4、通过 React Hook(函数式组件)

使用 React Hook(useRef 钩子)在函数式组件中创建 Refs同样非常简单。以下是一个具体的示例:

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

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

  useEffect(() => {
    
    
    // 在组件渲染后,可以访问DOM元素
    myRef.current.focus(); // 聚焦到DOM元素
  }, []);

  const focusInput = () => {
    
    
    // 在事件处理程序中访问Ref
    myRef.current.focus();
  };

  return (
    <div>
      <input ref={
    
    myRef} /> {
    
    /* 将Ref分配给input元素 */}
      <button onClick={
    
    focusInput}>Focus Input</button>
    </div>
  );
}

export default MyComponent;

在上面的示例中,我们首先使用 useRef(null) 创建一个Ref对象。useRef() 的参数是初始值,通常设置为 null,因为它在初始渲染时并不关心实际的值。

然后,我们使用 useEffect 钩子来模拟 componentDidMount 生命周期方法,在其中使用 myRef.current 访问DOM元素并将焦点聚焦到input上。useEffect 接受第二个参数,一个依赖数组,这里为空数组,表示只在组件的初始渲染时执行这个效果。

最后,我们在一个按钮的点击事件处理程序中再次使用Ref,将焦点聚焦到input上。

使用 useRef 钩子可以在函数式组件中方便地创建和访问Refs,以及执行与Refs相关的操作,而无需使用类组件。这种方式在React 16.8及之后的版本中可用。

三、例

3.1、焦点管理

以下是一个简单的 React 示例,演示如何使用 Refs 来管理焦点,具体是将焦点从一个输入框移动到另一个输入框。这个示例包括一个按钮,当点击按钮时,将焦点从一个输入框转移到另一个输入框。

import React, {
    
     Component } from 'react';

class FocusManagementExample extends Component {
    
    
  constructor(props) {
    
    
    super(props);
    this.inputRef1 = React.createRef(); // 创建 Ref for Input 1
    this.inputRef2 = React.createRef(); // 创建 Ref for Input 2
  }

  moveFocus = () => {
    
    
    this.inputRef2.current.focus(); // 移动焦点到 Input 2
  };

  render() {
    
    
    return (
      <div>
        <input ref={
    
    this.inputRef1} placeholder="Input 1" />
        <input ref={
    
    this.inputRef2} placeholder="Input 2" />
        <button onClick={
    
    this.moveFocus}>Move Focus to Input 2</button>
      </div>
    );
  }
}

export default FocusManagementExample;

在这个示例中,我们首先创建两个 Refs,this.inputRef1this.inputRef2,分别引用两个输入框。然后,在 moveFocus 方法中,我们使用 this.inputRef2.current.focus() 来将焦点移动到第二个输入框。当点击按钮时,调用 moveFocus 方法,焦点将从输入框 1 移动到输入框 2。

3.2、文本的选择

下面是一个简单的 React 示例,演示如何使用 Refs 来实现文本选择的功能。在这个示例中,有一个文本输入框和一个按钮,点击按钮后会选择文本输入框中的文本。

import React, {
    
     Component } from 'react';

class TextSelectionExample extends Component {
    
    
  constructor(props) {
    
    
    super(props);
    this.inputRef = React.createRef(); // 创建 Ref for the text input
  }

  selectText = () => {
    
    
    if (this.inputRef.current) {
    
    
      this.inputRef.current.select(); // 选择文本输入框中的文本
    }
  };

  render() {
    
    
    return (
      <div>
        <input ref={
    
    this.inputRef} placeholder="Type some text" />
        <button onClick={
    
    this.selectText}>Select Text</button>
      </div>
    );
  }
}

export default TextSelectionExample;

在这个示例中,我们首先创建一个 Ref this.inputRef 并将其分配给输入框。然后,我们定义了 selectText 方法,该方法使用 this.inputRef.current.select() 来选择文本输入框中的文本。当按钮被点击时,调用 selectText 方法,文本输入框的文本将被选中。

3.3、媒体的播放

以下是一个使用 React 来创建一个简单的媒体播放器的示例。这示例包括一个播放/暂停按钮、一个音频元素,以及一些状态管理来控制播放状态。

import React, {
    
     Component } from 'react';

class MediaPlayerExample extends Component {
    
    
  constructor(props) {
    
    
    super(props);
    this.audioRef = React.createRef(); // 创建 Ref for the audio element
    this.state = {
    
    
      isPlaying: false,
    };
  }

  togglePlay = () => {
    
    
    const audio = this.audioRef.current;

    if (this.state.isPlaying) {
    
    
      audio.pause();
    } else {
    
    
      audio.play();
    }

    this.setState({
    
     isPlaying: !this.state.isPlaying });
  };

  render() {
    
    
    return (
      <div>
        <audio ref={
    
    this.audioRef} controls>
          <source src="your-audio-file.mp3" type="audio/mpeg" />
          Your browser does not support the audio element.
        </audio>
        <button onClick={
    
    this.togglePlay}>
          {
    
    this.state.isPlaying ? 'Pause' : 'Play'}
        </button>
      </div>
    );
  }
}

export default MediaPlayerExample;

在这个示例中,我们首先创建一个 Ref this.audioRef 并将其分配给audio元素。然后,我们定义了 togglePlay 方法,该方法会根据当前播放状态(isPlaying)来播放或暂停音频,然后更新状态以反映新的播放状态。

<audio> 元素用于播放音频文件,并带有控件来控制播放。你可以在 <source> 元素的 src 属性中指定音频文件的URL。

按钮元素允许用户点击来切换播放/暂停状态,并在按钮上显示当前状态。

这是一个简单的媒体播放器示例,你可以根据实际需求扩展它以添加更多功能,例如音量控制、跳过、循环等功能。

3.4、强制触发动画

在 React 中,你可以使用 ref 来访问组件或 DOM 元素,以便在需要时强制触发动画。以下是一个简单的示例,演示如何使用 React 和 ref 来强制触发 CSS 动画:

import React, {
    
     Component } from 'react';

class AnimationExample extends Component {
    
    
  constructor(props) {
    
    
    super(props);
    this.animationBoxRef = React.createRef(); // 创建 Ref for the animated box
  }

  startAnimation = () => {
    
    
    const box = this.animationBoxRef.current;

    // 添加 CSS 类以触发动画
    box.classList.add('animate');

    // 在动画完成后,移除 CSS 类以重置动画
    box.addEventListener('animationend', () => {
    
    
      box.classList.remove('animate');
    });
  };

  render() {
    
    
    return (
      <div>
        <div
          ref={
    
    this.animationBoxRef}
          className="box"
        ></div>
        <button onClick={
    
    this.startAnimation}>Start Animation</button>
      </div>
    );
  }
}

export default AnimationExample;

在这个示例中,我们首先创建了一个 Ref this.animationBoxRef 并将其分配给一个 div 元素,该 div 元素表示动画的目标。然后,我们定义了 startAnimation 方法,该方法使用 classList 添加一个 CSS 类 animatediv 元素上,以触发动画。

在动画结束后,我们使用 addEventListener 监听 animationend 事件,并在事件处理程序中移除 CSS 类 animate 以重置动画状态。

按钮元素允许用户点击来触发动画。你可以在 CSS 中定义相应的动画效果,例如通过 @keyframes 规则来定义动画的细节。

3.5、继承三方 DOM 库

继承第三方 DOM 库通常需要在 React 中使用 ref 来访问和操作第三方库中的 DOM 元素。以下是一个示例,演示如何在 React 中继承第三方 DOM 库(这里以使用D3.js库为例):

首先,确保你的项目中已经引入了 D3.js 库,你可以使用 npm 或通过 <script> 标签将其添加到你的项目中。

import React, {
    
     Component } from 'react';
import * as d3 from 'd3'; // 引入 D3.js

class D3IntegrationExample extends Component {
    
    
  constructor(props) {
    
    
    super(props);
    this.svgRef = React.createRef(); // 创建 Ref for the SVG element
  }

  componentDidMount() {
    
    
    // 在组件挂载后,初始化 D3.js 操作
    const svg = d3.select(this.svgRef.current);

    // 在 SVG 中添加一个矩形
    svg
      .append('rect')
      .attr('x', 10)
      .attr('y', 10)
      .attr('width', 100)
      .attr('height', 50)
      .style('fill', 'blue');
  }

  render() {
    
    
    return (
      <div>
        <svg ref={
    
    this.svgRef} width={
    
    200} height={
    
    100}></svg>
      </div>
    );
  }
}

export default D3IntegrationExample;

在这个示例中,我们首先引入了 D3.js 库。然后,我们创建一个 Ref this.svgRef 并将其分配给一个 <svg> 元素,这个元素将用来绘制 D3.js 图形。

componentDidMount 生命周期方法中,我们使用 D3.js 的 d3.select 方法选择了这个 <svg> 元素,并在其中添加一个蓝色矩形。你可以根据 D3.js 的文档和需要来进行更复杂的操作。

这个示例演示了如何在 React 中继承第三方 DOM 库,特别是 D3.js。你可以根据你的项目需求,继承其他的第三方库,然后使用 ref 来访问和操作其 DOM 元素。

参考地址

chatgpt

https://zhuanlan.zhihu.com/p/549934728

猜你喜欢

转载自blog.csdn.net/weixin_35691921/article/details/134134998