React Hooks—— useRef用法及类组件的三种ref创建使用方式

useRef

ref使用场景

通常,当你的组件需要“跳出” React 并与外部 API 通信时,你会用到 ref —— 通常是不会影响组件外观的浏览器 API。以下是这些罕见情况中的几个:

  • 存储 timeout ID
  • 存储和操作 DOM 元素,涉及非受控组件。赋值给标签,目的是获取DOM元素;赋值给类组件,目的是获取组件的实例;
  • 存储不需要被用来计算 JSX 的其他对象。

如果你的组件需要存储一些值,但不影响渲染逻辑,请选择 ref。

类组件的三种创建和使用方式
方式一——字符串形式的ref(过时了,未来版本可能移除,开发时不推荐使用,效率低

通过 this.refs访问

<input ref="input1"/>
方式二——回调形式的ref
React帮我们调用回调函数,并且将当前的DOM节点传入回调函数
<input ref={(currentNode) => {this.input1 = currentNode}} />
// currentNode是当前所处的节点,也就是这个input

不能通过 this.refs访问,因为这些ref都成了实例属性

React不会帮你执行未知属性的回调函数

<input ref={c => this.input1 = c } ahh={() => {console.log(1)}} type="text" placeholder="点击按钮提示数据"/>

如果ref回调函数是以内联函数的形式定义的,在更新过程中它会被执行两次,第一次传入参数null,第二次传入参数DOM元素。这是因为在每次渲染时创建一个新的实例,所以React清空旧的ref并设置新的。通过将ref的回调函数定义成class的绑定函数的方式可以避免上述问题,但是大多数情况下它是无效的(无关紧要)

方式三——createRef创建ref容器(最推荐

React.createRef调用后可以返回一个容器,该容器可以存储被ref所标识的节点,该容器是“专人专用”的,多个ref的值可以相互独立

ref是实例的属性,不能通过this.refs访问

this.myRef.current是当前引用的DOM,this.myRef.current.value是当前DOM的值

myRef = React.createRef();
<input ref={this.myRef} />
hooks组件通过useRef创建ref对象

在函数组件中,可以基于 useRef获取DOM元素!类似于类组件中的 :

  • ref={x=>thix.box=x}
  • React.createRef

函数组件中创建ref对象的两种方法:

  • let box1 = useRef(null)
  • let box2 = React.createRef();

注意:

React.createRef也是ref对象,在类组件和函数组件中都可以使用

useRef只能在函数组件中使用,所有的hooks函数都只能在函数组件中使用,在类组件中使用会报错

ref只能在DOM创建之后才能获取DOM元素,也就是说在useLayoutEffect阶段就可以使用

createRef性能比useRef差——每次渲染创建新ref对象
  • createRef 每次渲染都会返回一个新的引用
  • 而 useRef 每次都会返回相同的引用
import React, { useState, useEffect, useRef } from "react";
import { Button } from 'antd';
import './Demo.less';

let prev1,
    prev2;
const Demo = function Demo() {
    let [num, setNum] = useState(0);
// 函数组件中创建ref对象的两种方法
    let box1 = useRef(null),
        box2 = React.createRef();
    if (!prev1) {
        // 第一次DEMO执行,把第一次创建的REF对象赋值给变量
        prev1 = box1;
        prev2 = box2;
    } else {
        // 第二次DEMO执行,我们验证一下,新创建的REF对象,和之前第一次创建的REF对象,是否一致?
        console.log(prev1 === box1); //true  useRef再每一次组件更新的时候(函数重新执行),再次执行useRef方法的时候,不会创建新的REF对象了,获取到的还是第一次创建的那个REF对象!!
        console.log(prev2 === box2); //false createRef在每一次组件更新的时候,都会创建一个全新的REF对象出来,比较浪费性能!!
        // 总结:在类组件中,创建REF对象,我们基于 React.createRef 处理;但是在函数组件中,为了保证性能,我们应该使用专属的 useRef 处理!!
    }

    useEffect(() => {
        console.log(box1.current);
        console.log(box2.current);
    });

    return <div className="demo">
        <span className="num" ref={box1}>{num}</span>
        <span className="num" ref={box2}>哈哈哈</span>
        <Button type="primary" size="small"
            onClick={() => {
                setNum(num + 1);
            }}>
            新增
        </Button>
    </div>;
};

总结:在类组件中,创建Ref对象,基于React.createRef处理;在函数组件中为了保证性能使用useRef

ref的DOM用法总结【useRef】
  • 给元素标签设置ref,目的:获取对应的DOM元素

  • 给类组件设置ref,目的:获取当前调用组件创建的实例(后续可以根据实例获取子组件中的相关信息)

    // 基于ref获取子组件的实例,这样基于实例,可以调用子组件内部,挂载到实例上的东西
    class Child extends React.Component {
        state = { x: 1000 };
        render() {
            return <div className="child-box">
                {this.state.x}
            </div>;
        }
    } 
    
  • 给函数组件/hooks设置ref,直接报错:Function components cannot be given refs. Attempts to access this ref wil fail,但是可以配合React.forwardRef实现ref的转发。目的:获取函数子组件内的某个DOM元素

    // 基于forwardRef实现ref转发,目的:获取子组件内部的某个元素
    const Child = React.forwardRef(function Child(props, ref) {
        // console.log(ref); //在DEMO中,调用Child的时候,传递的ref对象「x」
        return <div className="child-box">
            <span ref={ref}>哈哈哈</span>
        </div>;
    }); 
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值