useImperativeHandle是来解决什么问题的?
答:useImperativeHandle可以让父组件获取并执行子组件内某些自定义方法。本质上其实是子组件将自己内部的方法通过useImperativeHandle添加到父组件中useRef定义的对象中。
补充说明: 1、useRef创建引用变量 2、React.forwardRef将引用变量传递给子组件 3、useImperativeHandle将子组件内定义的方法作为属性,添加到父组件中的ref对象上。
因此,如果想使用useImperativeHandle,那么还要结合useRef、React.forwardRef一起使用。
useImperativeHandle的使用方法
正常情况下 ref 是不能挂在到函数组件上的,因为函数组件没有实例,但是useImperativeHandle 为我们提供了一个类似实例的东西。它帮助我们通过 useImperativeHandle 的第 2 个参数,所返回的对象的内容挂载到 父组件的 ref.current 上。这样父组件就可以操作子组件里的dom元素的属性和方法了。通过useImperativeHandle做代理,可以尽可能的多的限制对外暴露的方法和属性
forwardRef会创建一个React组件,这个组件能够将其接受的 ref 属性转发到其组件树下的另一个组件中。(Starting in React 19, you can now access ref as a prop for function components)
语法:
useImperativeHandle(ref, createHandle, [deps])
ref需要被赋值的ref对象。createHandle:createHandle函数的返回值作为ref.current的值。[deps]依赖数组,依赖发生变化会重新执行createHandle函数。
import React, { forwardRef, useImperativeHandle, useEffect, useRef } from 'react'
const TestRef = forwardRef((props, ref) => {
useImperativeHandle(ref, () => ({
open() {
console.log("open")
}
}))
})
function App () {
const ref = useRef()
useEffect(() => {
ref.current.open()
},[])
return(
<>
<div>测试测试</div>
<TestRef ref={ref}></TestRef>
</>
)
}
export default App
实践中帮我解决了什么问题
校招社招组件的封装中,有个下载图片的saveImg方法,之前写在了父组件,父组件直接调用方法保存图片,这样做,每次使用校招社招组件都需要自己写保存图片方法。如果将saveImg写到发布的公共组件中,需要将saveImg暴露给父组件,于是用了React.forwardRef和useImperativeHandle,如下
//子组件: 校招社招图片,公共组件
const QrcodeRender = forwardRef(ref => {
const {imgRef, saveImg} = useSaveImg();
useImperativeHandle(
ref,
() => ({
saveImg,
}),
[]
);
return (
<div ref={imgRef}></div>
)
})
// 父组件---浮层
const ReferralQrcodeModal: FC<Props> = () => {
const qrcodeRef = useRef<QRCodeComponent | null>(null);
const handleSaveImg = () => {
if (qrcodeRef.current) {
qrcodeRef.current.saveImg();
}
};
return (
<Modal
destroyOnClose
width={350}
className="referral-qrcode-modal"
open={isModalOpen}
onCancel={handleCancel}
okText="下载图片"
onOk={handleSaveImg}
closeIcon={<CloseCircleOutlined />}
>
<QrcodeRender ref={qrcodeRef}/>
</Modal>
);
};