WHAT - React 元素接收的 ref 详解

目录

  • [1. ref 的基本概念](#1. ref 的基本概念)
  • [2. 如何使用 ref](#2. 如何使用 ref)
    • [2.1 基本用法](#2.1 基本用法)
    • [2.2 类组件使用 createRef](#2.2 类组件使用 createRef)
  • [3. forwardRef 转发 ref](#3. forwardRef 转发 ref)
  • [4. ref 的应用场景](#4. ref 的应用场景)
  • [5. ref 和函数组件](#5. ref 和函数组件)
  • 总结

在 React 中,ref(引用)用于访问 DOM 元素或类组件实例。它允许我们直接与元素进行交互,而不需要依赖 React 的数据流。

下面是关于 React 元素接收 ref 的详细解释。

1. ref 的基本概念

React 中的 ref 主要有两种类型:

  • 字符串 ref:React 16.3 之前的用法,已经被废弃,不推荐使用。
  • 回调 ref :提供一个函数,将 ref 作为参数传递给该函数。可以访问 DOM 元素或组件实例。
  • createRef()或者useRef() :推荐的现代用法,允许创建一个 ref 对象,该对象可以用于访问 DOM 元素或类组件实例。

2. 如何使用 ref

2.1 基本用法

函数组件为例:

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

const MyComponent = () => {
  const myRef = useRef<HTMLInputElement>(null);

  useEffect(() => {
    if (myRef.current) {
      myRef.current.focus(); // 聚焦到 input 元素
    }
  }, []);

  return <input ref={myRef} />;
};

export default MyComponent;

在这个例子中,我们使用了 useRef 钩子创建一个 ref,并将它传递给一个 <input> 元素。这样,myRef.current 就指向该 input 元素,我们可以在 useEffect 中直接操作 DOM。

这里有一个技巧,前面提过 ref 支持接收回调函数,因此我们可以让代码更加简洁:

typescript 复制代码
import React, { useCallback } from 'react';

const MyComponent = () => {
  const myRef = useCallback((node) => node?.focus(), [])
  return <input ref={myRef} />;
};

export default MyComponent;

它的工作原理如下:

  • 当 DOM 节点添加到屏幕时,React 会以 DOM 节点作为参数调用该函数。
  • 当 DOM 节点被移除时,React 会以 null 调用该函数。

2.2 类组件使用 createRef

在类组件中,我们通常使用 React.createRef() 来创建 ref

typescript 复制代码
import React, { Component } from 'react';

class MyComponent extends Component {
  private myRef = React.createRef<HTMLInputElement>();

  componentDidMount() {
    if (this.myRef.current) {
      this.myRef.current.focus();
    }
  }

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

export default MyComponent;

3. forwardRef 转发 ref

如果你要在函数组件中使用 ref,并且希望该 ref 被传递到子组件中,你需要使用 React.forwardRef 来转发 ref

typescript 复制代码
import React, { forwardRef, useImperativeHandle, useRef } from 'react';

interface CustomInputProps {
  label: string;
}

const CustomInput = forwardRef<HTMLInputElement, CustomInputProps>((props, ref) => {
  const inputRef = useRef<HTMLInputElement>(null);

  // 允许父组件操作子组件的方法
  useImperativeHandle(ref, () => ({
    focus: () => {
      if (inputRef.current) {
        inputRef.current.focus();
      }
    }
  }));

  return (
    <div>
      <label>{props.label}</label>
      <input ref={inputRef} />
    </div>
  );
});

export default CustomInput;

在这个例子中,CustomInput 是一个函数组件,它通过 forwardRef 接收外部的 ref。我们通过 useImperativeHandle 将自定义的方法(如 focus)暴露给父组件。

在父组件使用时:

typescript 复制代码
import React, { useRef } from 'react';
import CustomInput from './CustomInput';

const ParentComponent = () => {
  const inputRef = useRef<{ focus: () => void }>(null);

  return (
    <div>
      <CustomInput ref={inputRef} label="Username" />
      <button onClick={() => inputRef.current?.focus()}>Focus Input</button>
    </div>
  );
};

export default ParentComponent;

4. ref 的应用场景

  • 访问 DOM 元素 :如上述例子,ref 允许你直接访问 DOM 元素并操作其属性,例如聚焦、滚动、选择文本等。
  • 与第三方库集成 :很多第三方库(如 D3.js 或 jQuery)需要直接操作 DOM 元素,这时 ref 就非常有用。
  • 获取组件实例 :虽然不推荐直接访问组件实例,但如果需要,可以通过 ref 来访问类组件的实例方法。

5. ref 和函数组件

默认情况下,ref 只能用于类组件或 DOM 元素。如果你尝试将 ref 直接传递给一个函数组件,React 会给出警告,表示函数组件无法接收 ref。为了让函数组件能够接收 ref,你需要使用 React.forwardRef

总结

  • ref 是 React 中访问 DOM 或组件实例的一种方式。
  • 函数组件无法直接使用 ref,需要使用 React.forwardRef 转发 ref
  • ref 可以配合 useImperativeHandle 定制暴露给父组件的接口。
  • ref 对于与第三方库集成和直接操作 DOM 元素非常有用。
相关推荐
wearegogog1233 小时前
基于 MATLAB 的卡尔曼滤波器实现,用于消除噪声并估算信号
前端·算法·matlab
Drawing stars3 小时前
JAVA后端 前端 大模型应用 学习路线
java·前端·学习
品克缤3 小时前
Element UI MessageBox 增加第三个按钮(DOM Hack 方案)
前端·javascript·vue.js
小二·3 小时前
Python Web 开发进阶实战:性能压测与调优 —— Locust + Prometheus + Grafana 构建高并发可观测系统
前端·python·prometheus
小沐°3 小时前
vue-设置不同环境的打包和运行
前端·javascript·vue.js
qq_419854054 小时前
CSS动效
前端·javascript·css
烛阴4 小时前
3D字体TextGeometry
前端·webgl·three.js
桜吹雪4 小时前
markstream-vue实战踩坑笔记
前端
南村群童欺我老无力.5 小时前
Flutter应用鸿蒙迁移实战:性能优化与渐进式迁移指南
javascript·flutter·ci/cd·华为·性能优化·typescript·harmonyos
C_心欲无痕5 小时前
nginx - 实现域名跳转的几种方式
运维·前端·nginx