一、概念
useImperativeHandle可以让父组件获取并执行子组件内某些自定义函数(方法)。本质上其实是子组件将自己内部的函数(方法)通过useImperativeHandle添加到父组件中useRef定义的对象中。
注意:
1、useRef创建引用变量
2、React.forwardRef将引用变量传递给子组件
3、useImperativeHandle将子组件内定义的函数作为属性,添加到父组件中的ref对象上。
因此,如果想使用useImperativeHandle,那么还要结合useRef、React.forwardRef一起使用。
二、React.forwardRef
React.forwardRef 会创建一个React组件,这个组件能够将其接受的 ref 属性转发到其组件树下的另一个组件中。
这种技术并不常见,但在以下两种场景中特别有用:
(1)转发 refs 到 DOM 组件
(2)在高阶组件中转发 refs
React.forwardRef 接受渲染函数作为参数。React 将使用 props 和 ref 作为参数来调用此函数。此函数应返回 React 节点。
二、基本用法
useImperativeHandle(ref,create,[deps])函数前2个参数为必填项,第3个参数为可选项。
第1个参数为父组件定义的useRef的值;
第2个参数为子组件要附加给ref的对象,该对象中的属性即子组件想要暴露给父组件的函数(方法);
第3个参数为可选参数,为函数的依赖变量。凡是函数中使用到的数据变量都需要放入deps中,如果处理函数没有任何依赖变量,可以忽略第3个参数。
请注意:
1、这里面说的“勾住子组件内自定义函数”本质上是子组件将内部自定义的函数添加到父组件的ref.current上面。
2、父组件若想调用子组件暴露给自己的函数,可以通过 ref.current.xxx 来访问或执行
1、实际案例
父组件调用子组件里面的方法
父组件
import { useRef } from "react";
import C from "./c";
export default () => {
const childRef = useRef();
const childAdd = () => {
//父组件调用子组件内部 add函数
childRef.current.add();
};
return (
<div>
<div>父组件</div>
{/* 父组件通过给子组件添加 ref 属性,将childRef传递给子组件,
子组件获得该引用即可将内部函数添加到childRef中 */}
<C ref={childRef}></C>
<button onClick={childAdd}>调用子组件里面的add方法</button>
</div>
);
};
子组件
import React, { useImperativeHandle } from 'react'
import { useState } from 'react'
/**
* 就可以接收到父组件传过来的ref
*/
export default React.forwardRef((props, ref) => {
const [num, setNum] = useState(1)
const add = () => {
console.log("我是A组件里面的方法")
setNum(num + 1)
}
/**
* 第一个参数是ref,父组件传过来的
* 我们想要把方法挂载的ref
*
* 第二个参数是一个方法,必须有返回值
* 返回的值就是要挂再到useRef上面的值
*
* 第三个参数是依赖项 依赖项改变的情况第一个参数
* 会重新调用,如果依赖项不传则每次render都会调用
*/
useImperativeHandle(ref, () => {
return {
add
}
/**
* 如果依赖项传一个空数组
* 则第一个方法只会在初始化的时候调用一次
* 里面的值不是最新的
*/
}, [num])
return (
<div>
<div>哈哈 我是A组件要使用imperative--{num}</div>
</div>
)
})