react中ref的使用(useRef,forwardRef,useImperativeHandle,createRef)

文章目录

  • 一、什么是ref
  • 二、在函数式组件中使用ref
    • [1. useRef 获取dom](#1. useRef 获取dom)
    • [2. forwardRef获取子组件的dom](#2. forwardRef获取子组件的dom)
    • [3. useImperativeHandle将某些指定的行为暴露给父组件](#3. useImperativeHandle将某些指定的行为暴露给父组件)
  • 三、在类组件中使用ref
    • [1. createRef](#1. createRef)
    • [2. 回调函数](#2. 回调函数)
    • [3. 字符串](#3. 字符串)

一、什么是ref

在React中,ref是一个用于访问真实DOM节点或者React组件实例的对象。它允许您在组件中直接操作DOM元素或组件,而无需遵循传统的数据流。

使用ref,您可以:

  1. 访问和操作DOM:ref允许您通过将ref对象传递给组件中的元素来访问和修改真实的DOM。您可以使用ref来获取输入框的值、改变元素的样式、添加/删除/更新元素等等。

  2. 访问和调用组件方法:ref允许您访问在组件类上定义的方法。这对于在某些情况下需要从父组件中直接访问子组件的方法非常有用。

  3. 获取组件实例和进行事件监听:当使用类组件时,ref可以用来获取组件的实例,以便在需要时进行其他操作。您还可以使用ref来进行事件监听,例如在某个特定的事件发生时执行某些操作。

需要注意的是,在大多数情况下,最好遵循React的数据流原则,尽量避免直接操作DOM或访问子组件的方法。只有当没有其他合适的选择并且确实需要这样做时,才应该使用ref。因为直接操作DOM或访问子组件的方法可能会破坏组件的封装性和可重用性。

二、在函数式组件中使用ref

1. useRef 获取dom

在React中,函数式组件使用ref属性可以获取到组件的实例或者某个Dom元素的引用。使用ref可以让你更方便地控制组件或Dom元素,并且可以在需要的时候访问和修改它们的属性和方法。

要在函数式组件中使用ref,你可以使用React提供的useRef钩子函数。举一个例子,假设我们有一个函数式组件MyComponent,其中包含了一个input元素:

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

const MyComponent = () => {
  const inputRef = useRef(null);

  const handleClick = () => {
    // 使用 useRef 返回的 ref 对象来访问 input 的属性和方法
    console.log(inputRef.current.value);
    inputRef.current.focus();
  };

  return (
    <div>
      <input ref={inputRef} type="text" />
      <button onClick={handleClick}>Focus Input</button>
    </div>
  );
};

export default MyComponent;

上述例子中,我们使用useRef钩子函数来创建了一个名为inputRef的引用。我们将这个引用传递给了input元素的ref属性,这样就可以通过inputRef.current来获取该input的引用。

在函数式组件的handleClick函数中,我们可以通过inputRef.current访问到input元素并获取到它的值。我们还可以使用inputRef.current.focus()来让input元素获得焦点。

通过使用ref,我们可以方便地操纵组件或Dom元素,进行一些需要访问或修改属性和方法的操作。
注意,ref只能在函数式组件中使用,并且不能在函数式组件的子组件上使用

2. forwardRef获取子组件的dom

在React中,函数式组件的子组件上可以使用forwardRef来使用refforwardRef函数可以将ref传递给子组件,从而在子组件中使用ref

下面是一个示例,展示了如何在函数式组件的子组件中使用ref

js 复制代码
import React, { forwardRef } from 'react';
 
// 子组件
const ChildComponent = forwardRef((props, ref) => {
  return (
    <input type="text" ref={ref} />
  );
});
 
// 父组件
const ParentComponent = () => {
  // 创建一个ref
  const inputRef = React.createRef();
  // 使用ref传递给子组件
  return (
    <div>
      <ChildComponent ref={inputRef} />
      <button onClick={() => inputRef.current.focus()}>聚焦输入框</button>
    </div>
  );
};
 
export default ParentComponent;

在上面的例子中,ChildComponent是一个函数式组件,通过将ref作为forwardRef的第二个参数,将其传递给内部的input元素。然后,可以在ParentComponent中创建一个ref并将其传递给ChildComponent。这样,我们就可以在父组件中操作子组件的input元素,例如调用focus()方法。

在按钮的onClick事件处理函数中,我们可以通过inputRef.current来获得子组件的input元素,并调用它的focus()方法将焦点聚焦到输入框上。

3. useImperativeHandle将某些指定的行为暴露给父组件

在React中,通过使用useImperativeHandle钩子函数,函数式组件可以将某些指定的行为暴露给父组件。这在一些情况下非常有用,例如限制某些DOM行为,让父组件能够直接操作该组件的某些功能。

下面是一个例子,演示如何使用useImperativeHandle来限制DOM行为:

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

// 子组件
const ChildComponent = forwardRef((props, ref) => {
  const childRef = useRef(null);

  // 定义待暴露的函数
  useImperativeHandle(ref, () => ({
    // 在这里暴露特定的DOM行为
    focus: () => {
      childRef.current.focus();
    },
    // 在这里暴露特定的DOM行为
    blur: () => {
      childRef.current.blur();
    }
  }));

  return <input ref={childRef} />;
});

// 父组件
const ParentComponent = () => {
  const childRef = useRef(null);

  const handleFocus = () => {
    childRef.current.focus();  // 子组件的focus函数被父组件调用
  };

  const handleBlur = () => {
    childRef.current.blur();   // 子组件的blur函数被父组件调用
  };

  return (
    <div>
      <ChildComponent ref={childRef} />
      <button onClick={handleFocus}>Focus</button>
      <button onClick={handleBlur}>Blur</button>
    </div>
  );
};

export default ParentComponent;

在上面的例子中,ChildComponent是一个简单的函数式组件,它包含了一个<input>元素。通过使用useImperativeHandle钩子函数,并将ref作为第一个参数传递进去,我们可以定义需要暴露给父组件的函数(在这里是focusblur)。这意味着父组件可以通过ref引用子组件,然后直接调用子组件的focusblur函数。

ParentComponent中,通过使用useRef来创建一个childRef引用。然后,在handleFocushandleBlur函数中,通过childRef.current来访问ChildComponent函数组件的focusblur函数,从而直接操控子组件的DOM行为。

这样,我们就可以在父组件中通过按钮点击来控制子组件的DOM行为,实现了对DOM行为的限制。

三、在类组件中使用ref

1. createRef

在类式组件中,可以使用React.createRef()来创建一个ref对象,然后将该ref对象附加到component的一个元素上,通过ref对象可以引用该元素并对其进行操作。

下面是一个使用ref的示例:

js 复制代码
import React from "react";

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    
    this.myDivRef = React.createRef(); // 创建一个ref对象
  }
  
  handleClick = () => {
    this.myDivRef.current.style.backgroundColor = "blue"; // 使用ref对象引用元素并对其进行操作
  }
  
  render() {
    return (
      <div>
        <div ref={this.myDivRef}>Hello, world!</div> {/* 将ref对象附加到元素上 */}
        <button onClick={this.handleClick}>Change Color</button>
      </div>
    );
  }
}

export default MyComponent;

在上面的示例中,我们首先在类的构造函数中创建一个ref对象myDivRef。然后,通过将myDivRef作为<div>元素的ref属性值,我们可以将ref对象附加到这个元素上。在handleClick方法中,我们通过this.myDivRef.current引用该元素并改变其背景颜色为蓝色。

这样,当点击按钮时,就会调用handleClick方法,从而改变被ref引用的<div>元素的背景颜色。

2. 回调函数

通过回调函数来设置ref,在回调函数中将DOM元素分配给组件的实例属性。在组件的实例中,可以通过属性来访问该DOM元素。

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

class ExampleComponent extends Component {
  constructor(props) {
    super(props);
    this.myRef = null;
    this.setRef = element => {
      this.myRef = element;
    };
  }

  componentDidMount() {
    console.log(this.myRef); // 访问DOM元素
  }

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

3. 字符串

使用字符串的ref属性来获取DOM元素。这种方式在React v16.3之前是支持的,但在较新的版本中已经过时,不建议使用。

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

class ExampleComponent extends Component {
  componentDidMount() {
    console.log(this.refs.myRef); // 访问DOM元素
  }

  render() {
    return <div ref="myRef">Example</div>;
  }
}
相关推荐
该用户已不存在11 分钟前
这6个网站一旦知道就离不开了
前端·后端·github
Ai行者心易15 分钟前
10天!前端用coze,后端用Trae IDE+Claude Code从0开始构建到平台上线
前端·后端
东东23323 分钟前
前端开发中如何取消Promise操作
前端·javascript·promise
掘金安东尼28 分钟前
官方:什么是 Vite+?
前端·javascript·vue.js
柒崽29 分钟前
ios移动端浏览器,vh高度和页面实际高度不匹配的解决方案
前端
渣哥1 小时前
你以为 Bean 只是 new 出来?Spring BeanFactory 背后的秘密让人惊讶
javascript·后端·面试
烛阴1 小时前
为什么游戏开发者都爱 Lua?零基础快速上手指南
前端·lua
大猫会长1 小时前
tailwindcss出现could not determine executable to run
前端·tailwindcss
Moonbit1 小时前
MoonBit Pearls Vol.10:prettyprinter:使用函数组合解决结构化数据打印问题
前端·后端·程序员
533_1 小时前
[css] border 渐变
前端·css