一、前言:
众所周知,函数组件是没有实例的,所以是没有自己的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。
网友评论