useImperativeHandle的使用方法

12 阅读2分钟

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对象。
  • createHandlecreateHandle函数的返回值作为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>
  );
};