个人公众号

公众号文章-React中ref的四种使用方法
个人公众号,求关注公众号~ 求指导,求点赞,求评论。

写在前面的废话

什么时候使用ref的环境就不说了,比如我们要获取一个输入框的value,无法通过state去获取,这时候用ref就很合适。

本文的重点介绍的是ref的四种方法,因为现在使用的react版本是18.2,所以部分的方法都算是已经过时了,并有自己的局限性,所以如果方便,更推荐使用useRef的方式。

stringRef

在描述stringRef之前,先贴上一段官网中关于stringRef的描述。

如果你以前使用过 React,你可能熟悉一个较旧的 API,其中属性是一个字符串,比如 ,而 DOM 节点被访问为 .我们建议不要这样做,因为字符串引用存在一些问题,被认为是遗留的,并且可能会在将来的某个版本中删除。
在知道了字符串的ref问题之后,由于部分旧的代码我们还会使用到stringRef,我们还是得看看stringRef的使用。

import { PureComponent, ReactNode } from "react";class RefComponent extends PureComponent {
  handleClick = () => {
    const element: any = this.refs.stringRef;
    console.log(element?.value);
  };
  render(): ReactNode {
    return (
      <div>
        <input ref="stringRef" />
        <button
          onClick={() => {
            this.handleClick();
          }}
        >
          点击获取输入框的值
        </button>
      </div>
    );
  }
}export default RefComponent;

效果如下:
在这里插入图片描述

当点击了我们的按钮的时候,就直接获取到了输入框中的值。

而在控制台中也有这么一个警告

Warning: A string ref, “stringRef”, has been found within a strict
mode tree. String refs are a source of potential bugs and should be
avoided. We recommend using useRef() or createRef() instead.

Learn more about using refs safely here:
https://reactjs.org/link/strict-mode-string-ref

而这个警告也与官网的提示一样,讲述了stringRef是一个"deprecated"的API,建议我们使用useRef或者是createRef这两个API。
除此之外,在第五行的代码中,由于我们使用了this,而只有在类组件中,才存在了this,因此我们无法在函数组件中使用到stringRef。
综上所述,不建议再使用stringRef,除非你的项目很老,只能使用stringRef。

createRef

相对于stringRef,createRef算是比较正常点的,而因为stringRef有bug的原因,所以react也推荐在class组件使用createRef。

与直接使用stringRef不同,我们需要先在constructor中,使用createRef构建一个ref对象,再将其绑定到元素上去,这样子才可以去获取到元素。代码如下:

import React, { PureComponent, ReactNode, RefObject } from "react";class RefComponent extends PureComponent {
  inputRef: RefObject<HTMLInputElement> | undefined;
  constructor(props: {} | Readonly<{}>) {
    super(props);
    this.inputRef = React.createRef();
  }
  handleClick = () => {
    const element: any = this.inputRef;
    console.log(element?.current?.value);
  };
  render(): ReactNode {
    return (
      <div>
        <input ref={this.inputRef} />
        <button
          onClick={() => {
            this.handleClick();
          }}
        >
          点击获取输入框的值
        </button>
      </div>
    );
  }
}export default RefComponent;


需要注意的是,我们无法再直接使用ref.value的方式去获取到值,而是需要使用ref?.current?.value的方式获取到值。

而将createRef放置在constructor中的原因,是因为如果放在

componentDidMount的时候,很容易出现createRef未能完成初始化,会出现undefined,同时,也最好使用?.的形式,防止放在constructor的时候,也未能及时初始化的情况。
同样的,本代码也只能放在类组件中使用,无法放在函数组件中使用,因为没有this…
也需要注意一点,这儿我用的类型是RefObject,而部分同学喜欢用LegacyRef,后者泛指的是Ref类型,是兼容之前stringRef的版本。
效果如下:
在这里插入图片描述

CallbackRef

ref属性,除了可以接受ref对象之外,也可以接受函数,这就称之为CallbackRef,也没啥好讲的,代码如下

import React, { LegacyRef, PureComponent, ReactNode, RefObject } from "react";class RefComponent extends PureComponent {
  inputRef: HTMLElement | undefined | null;handleClick = () => {
    const element: any = this.inputRef;
    console.log(element?.value);
  };
  render(): ReactNode {
    return (
      <div>
        <input
          ref={(ref) => {
            this.inputRef = ref;
          }}
        />
        <button
          onClick={() => {
            this.handleClick();
          }}
        >
          点击获取输入框的值
        </button>
      </div>
    );
  }
}export default RefComponent;

需要注意的是,这次的inputRef并不是RefObject,而是一个html对象,所以我们只需要当他做一个html对象处理就好了。

唯一要注意的是,依旧需要在类组件中使用,无法在函数组件中使用,毕竟都是对ref的操作。

useRef

与前面的类组件中对ref对象的操作,函数组件在获得了hook之后,也出现了对应的useRef钩子与之对应。毕竟ref对象都是只能在类组件中使用,前三个方式,无论怎么说,本质都是在类组件中对ref属性做一些变种,而useRef在函数式编程为王道的今天,更加的需要了解。
useRef返回的是一个可变的ref对象,类型为refObject,所以依旧需要用到上面的current属性去读取我们要的值。
useRef需要我们先使用userRef,接着在ref属性上使用回调函数的方式绑定ref。代码如下:

import { useRef } from "react";function RefComponent() {
  const inputRef = useRef<HTMLElement | null>();
  const handleClick = () => {
    const element: any = inputRef;
    console.log(element?.current?.value);
  };
  return (
    <>
      <input
        ref={(ref) => {
          inputRef.current = ref;
        }}
      />
      <button
        onClick={() => {
          handleClick();
        }}
      >
        点击获取输入框的值
      </button>
    </>
  );
}
export default RefComponent;


效果如下:

在这里插入图片描述

最后的废话

大人,现在已经是2023年的年尾了,别想那么多了,用useRef吧…不要搞那么多事情了。

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐