ForwardRef useImperativeHandle方法怎么使用
一、获取Ref的方式
使用字符串
使用函数
使用Ref对象(最常见)
使用createRef
export class RefTest extends React.Component {
currentDom: React.RefObject = React.createRef();
currentChildren: React.LegacyRef = React.createRef();
render() {
console.log(this.currentChildren, this.currentDom);
return (
<>
你好
>
)
}
} 
使用useRef
export const RefTest = () => {
const currentDom = useRef(null);
const currentChildren = useRef(null);
useEffect(() => {
console.log(currentChildren, currentDom, '这里也可以打印出来了');
},[])
return (
<>
你好
>
)
}二、Ref实现组件通信
既然ref可以获取到子组件的实例,那么就可以拿到子组件上的状态和方法,从而可以实现组件之间的通信
来个极简版

import React, { useEffect } from 'react';
class Son extends React.Component{
state={
sonValue:''
}
render(){
return
子组件的信息: {this.state.sonValue}
对父组件说
this.props.setFather(e.target.value)}/>
}
}
export default function Father(){
const [ fatherValue , setFatherValue ] = React.useState('')
const sonRef = React.useRef(null)
return
父组件的信息: {fatherValue}
对子组件说
sonRef.current.setState( {sonValue: e.target.value})}/>
}
三、ForwardRef
上面说的三种都是组件去获取其DOM元素或者子组件的实例,当开发变得复杂时,我们可能有将ref跨层级捕获的需求,也就是可以将ref进行转发
比如跨层级获取ref信息

来个例子, 我们希望能够在GrandFather组件获取到Son组件中
![图片转存失败,建议将图片保存下来直接上传
import React from 'react';
interface IProps {
targetRef: React.RefObject
otherProps: string
}
interface IGrandParentProps {
otherProps: string
}
class Son extends React.Component {
constructor(props) {
super(props);
console.log(props,'son中的props');
}
render() {
// 最终目标是获取该DOM元素的信息
return 真正目的是这个
}
}
class Farther extends React.Component {
constructor(props) {
super(props)
console.log(props, 'father中的props');
}
render() {
return (
// 继续将ref传给Son
)
}
}
// 在这里使用了forwardRef, 相当于把传入的ref转发给Father组件
const ForwardRef = React.forwardRef((props: IGrandParentProps, ref: React.RefObject)
=> )
image.png(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/5d49e7ff4ec940b28dcb3a780fd5c0a7~tplv-k3u1fbpfcp-watermark.image?)
export class GrandFather extends React.Component {
currentRef:React.RefObject = React.createRef();
componentDidMount() {
// 获取到的Ref信息
console.log(this.currentRef, 'componentDidMount');
}
render() {
return (
)
}
}
]() 打印结果: 其实就是利用了forwardRef,把 ref 变成了可以通过 props 传递和转发

四、 useImperativeHandle
上面我们一直说的都是获取子组件的实例,但是实际上我们函数组件是没有实例的,故我们需要借助useImperativeHandle, 使用forwardRef+useImperativeHandle就可以在函数组件中流畅地使用ref
useImperativeHandle可以传入三个参数:
ref: 可以接受forwardRef传入的ref
handleFunc: 返回值作为暴露给父组件的ref对象
deps: 依赖项,当依赖项改变的时候更新形成的ref对象
看完参数其实就能够清楚地知道它的作用了,可以通过forwardRef+useImperativeHandle自定义获取到的ref信息
再来两个简单例子:
import { forwardRef, useEffect, useImperativeHandle, useRef, useState } from "react"
const ForwardItem = forwardRef((props, ref) => {
const [sonValue, setSonValue] = useState('修改之前的值');
useImperativeHandle(ref, () => ({
setSonValue,
}))
return (
子组件的值: {sonValue}
)
})
export const Father = () => {
const testRef = useRef(null);
useEffect(() => {
console.log(testRef.current, 'ref获取到的信息')
})
const changeValue = () => {
const DURATION = 2000;
setTimeout(() => {
testRef.current.setSonValue('我已经修改值啦')
},DURATION)
}
return (
<>
>
)
}父组件希望直接调用函数子组件的方法
这里让useImperativeHandle形成了有setSonValue的ref对象,然后再在父组件调用该方法
父组件希望获取到子组件的某个DOM元素
const ForwardItem = forwardRef((props, ref) => {
const elementRef: RefObject = useRef();
useImperativeHandle(ref, () => ({
elementRef,
}))
return (
我是一个子组件
)
})
export const Father = () => {
const testRef = useRef(null);
useEffect(() => {
console.log(testRef.current, 'ref获取到的信息')
})
return (
<>
>
)
} 