官网参考:
https://react.docschina.org/reference/react/useImperativeHandle
useImperativeHandle
useImperativeHandle 是 React 中的一个 Hook,它能让你自定义由 ref 暴露出来的句柄。
useImperativeHandle(ref, createHandle, dependencies?)
使用方法
向父组件暴露一个自定义的 ref 句柄
默认情况下,组件不会将它们的 DOM 节点暴露给父组件。举例来说,如果你想要 MyInput 的父组件 能访问到<input>
DOM 节点,你必须选择使用 forwardRef:。
import { forwardRef } from 'react';
const MyInput = forwardRef(function MyInput(props, ref) {
return <input {...props} ref={ref} />;
});
在上方的代码中,MyInput 的 ref 会接收到 <input>
DOM 节点。然而,你可以选择暴露一个自定义的值。为了修改被暴露的句柄,在你的顶层组件调用 useImperativeHandle:
import { forwardRef, useImperativeHandle } from 'react';
const MyInput = forwardRef(function MyInput(props, ref) {
useImperativeHandle(ref, () => {
return {
// ... 你的方法 ...
};
}, []);
return <input {...props} />;
});
注意在上述代码中,该 ref 已不再被转发到<input>
中。
假设你不想暴露出整个 <input>
DOM 节点,但你想要它其中两个方法:focus 和 scrollIntoView。为此,用单独额外的 ref 来指向真实的浏览器 DOM。然后使用 useImperativeHandle 来暴露一个句柄,它只返回你想要父组件去调用的方法:
import { forwardRef, useRef, useImperativeHandle } from 'react';
const MyInput = forwardRef(function MyInput(props, ref) {
const inputRef = useRef(null);
useImperativeHandle(ref, () => {
return {
focus() {
inputRef.current.focus();
},
scrollIntoView() {
inputRef.current.scrollIntoView();
},
};
}, []);
return <input {...props} ref={inputRef} />;
});
现在,如果你的父组件获得了 MyInput 的 ref,就能通过该 ref 来调用 focus 和 scrollIntoView 方法。然而,它的访问是受限的,无法读取或调用下方 <input>
DOM 节点的其他所有属性和方法。
实例
App.js
import { useRef } from 'react';
import MyInput from './MyInput.js';
export default function Form() {
const ref = useRef(null);
function handleClick() {
ref.current.focus();
// 下方代码不起作用,因为 DOM 节点并未被暴露出来:
// ref.current.style.opacity = 0.5;
}
return (
<form>
<MyInput label="Enter your name:" ref={ref} />
<button type="button" onClick={handleClick}>
Edit
</button>
</form>
);
}
MyInput.js
import { forwardRef, useRef, useImperativeHandle } from 'react';
const MyInput = forwardRef(function MyInput(props, ref) {
const inputRef = useRef(null);
useImperativeHandle(ref, () => {
return {
focus() {
inputRef.current.focus();
},
scrollIntoView() {
inputRef.current.scrollIntoView();
},
};
}, []);
return <input {...props} ref={inputRef} />;
});
export default MyInput;
更多例子
子组件:
import React, { useCallback, useImperativeHandle, memo, forwardRef } from 'react'
export default memo(forwardRef(function FormCreator(props, ref) {
useImperativeHandle(ref, () => {
return {
onFinish
}
})
const onFinish = (values) => {
console.log(values);
props?.onSubmit(values); // 调用父组件方法
};
return (
<>
<Form onFinish={onFinish}></Form>
</>
)
}));
父组件index.js
import React, { useRef } from 'react'
import FormCreator from '../../components/FormCreator'
export default function City() {
const form = useRef();
const onSubmit = useCallback((values) => {
console.log(values, 'values');
}, []);
//拿到子组件的方法
const test = ()=>{
console.log(form.current.onFinish)
}
return (
<>
<FormCreator conf={cityConf} ref={form} onSubmit={onSubmit} />
</>
)
}