如何实现拿到子组件是函数组件的ref?

2023-03-20  本文已影响0人  不详7

一、前言

众所周知,函数组件是没有实例的,所以是没有自己的ref的,如果使用useRef()来定义,始终是null,所以如何拿到子组件是函数组件的ref呢?我们使用的是forwardRef 和useImperativeHandle结合的方式。

二、介绍forwardRef 

React.forwardRef 会创建一个React组件,这个组件能够将其接受的 ref 属性转发到其组件树下的另一个组件中。这种技术并不常见,但在以下两种场景中特别有用:

1、转发 refs 到 DOM 组件

2、在高阶组件中转发 refs

总结:forwardRef 就是允许将子组件中某个组件的ref,透传给他的父组件。

用法示例:

import React, { forwardRef, useImperativeHandle, useRef } from 'react';

//A---父组件

const A = ()=>{

    const bRef = useRef(null)

    return (<B  ref={bRef} />)

}

//B---子组件,C---子子组件

const  B =   forwardRef ((props,ref)=>{

    let b='这是个变量'

    const b1=()=>{};

    const b2=()=>{};

    return <C  ref={ref} />

})

上述中bRef 拿到的就是C的ref,但是有个前提C组件必须是个类组件 不能是函数组件,或者C是个input这一类的基础标签。

注意:这个时候bRef ,只有C实例上面的方法和dom,是没有b变量和b1、b2方法的。那如果想让bRef有B组件的b变量和b1方法,就需要用到useImperativeHandle。

三、介绍useImperativeHandle

useImperativeHandle可以让你在使用ref时自定义暴露给父组件的实例值。在大多数情况下,应当避免使用ref这样的命令式代码。useImperativeHandle应当与forwardRef一起使用。

用法:useImperativeHandle(ref, createHandle, [deps])。

通过useImperativeHandle可以只暴露特定的操作,将父组件传入的ref和useImperativeHandle第二个参数返回的对象绑定到了一起。

作用: 减少暴露给父组件获取的DOM元素属性, 只暴露给父组件需要用到的DOM方法。

示例:解决上面bRef中没有b变量和b1方法问题。

A组件不变:

const A = ()=>{    const bRef = useRef(null)    return (<B  ref={bRef} />)}

把上面例子中B组件改写为:

const  B =   forwardRef ((props,ref)=>{

     let b='这是个变量'

     const b1=()=>{};

      const b2=()=>{};

     useImperativeHandle(ref, () => ({    b: b,    b1: b1  }));//仅仅多了一行代码,需要什么传什么

     return <C  ref={ref} />

})

此时在父组件A中的bRef中,不仅有C的ref全部内容,也有了子组件B的 b变量和b1方法 ,间接实现了 父组件拿到子组件是函数组件的ref。

上一篇 下一篇

猜你喜欢

热点阅读