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 元素非常有用。
相关推荐
liangshanbo12155 分钟前
请求拦截器相关面试题
java·前端·javascript
ShawnLiaoking7 分钟前
ADS305 Big Data Lecuture4 Web Scraping
大数据·前端
liangshanbo12158 分钟前
React面试题:Hooks 为什么不能在分支和循环里面写?
前端·javascript·react.js
FungLeo11 分钟前
成为全栈·Next.js 网站前台篇·响应式、可访问性与错误状态:内容站不能只验桌面首页
react.js·响应式设计·next.js·移动端适配·成为全栈·web 可访问性
开开心心就好12 分钟前
视频压缩工具推荐,绿色版免安装双击即用
java·前端·人工智能·spring·智能手机·intellij-idea·excel
西红柿炖牛腩35415 分钟前
GLB 转 OBJ/PLY 后体积没变?3D 模型不减面变小靠什么
前端·javascript·3d
欣欣之王来了22 分钟前
前端开发学习路线图:2026年Vue方向最新版
前端·学习·架构·项目·vue3教程
夏幻灵25 分钟前
前端八股:Vue2 与 Vue3 的核心区别:响应式、Composition API 与性能优化
前端
ss2731 小时前
AI全栈实战 | 3.5-01 Python 全栈前端最小集:不会 React 也能做出能看的后台,关键就一条线
前端·python·react.js