useImperativeHandle
是一个 React Hook,它允许你自定义作为 ref 公开的句柄。
useImperativeHandle(ref, createHandle, dependencies?)
参考
useImperativeHandle(ref, createHandle, dependencies?)
在组件的顶层调用 useImperativeHandle
来自定义它公开的 ref 句柄
import { forwardRef, useImperativeHandle } from 'react';
const MyInput = forwardRef(function MyInput(props, ref) {
useImperativeHandle(ref, () => {
return {
// ... your methods ...
};
}, []);
// ...
参数
-
ref
: 你从forwardRef
渲染函数 的第二个参数接收到的ref
。 -
createHandle
: 一个不接受任何参数并返回你想要公开的 ref 句柄的函数。该 ref 句柄可以具有任何类型。通常,你将返回一个包含你想要公开的方法的对象。 -
可选
dependencies
:createHandle
代码中引用的所有反应式值的列表。反应式值包括 props、state 以及在组件主体中直接声明的所有变量和函数。如果你的代码检查器已 针对 React 配置,它将验证每个反应式值是否已正确指定为依赖项。依赖项列表必须具有恒定的项目数量,并且必须像[dep1, dep2, dep3]
一样内联编写。React 将使用Object.is
比较将每个依赖项与其之前的 value 进行比较。如果重新渲染导致某些依赖项发生更改,或者你省略了此参数,则你的createHandle
函数将重新执行,并且新创建的句柄将分配给 ref。
返回值
useImperativeHandle
返回 undefined
。
使用
向父组件公开自定义 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 {
// ... your methods ...
};
}, []);
return <input {...props} />;
});
请注意,在上面的代码中,ref
不再转发到<input>
。
例如,假设您不想公开整个<input>
DOM 节点,但您想公开其两种方法:focus
和 scrollIntoView
。为此,请将真实的浏览器 DOM 保留在单独的 ref 中。然后使用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,它将能够调用其上的focus
和 scrollIntoView
方法。但是,它将无法完全访问底层的<input>
DOM 节点。
import { useRef } from 'react'; import MyInput from './MyInput.js'; export default function Form() { const ref = useRef(null); function handleClick() { ref.current.focus(); // This won't work because the DOM node isn't exposed: // ref.current.style.opacity = 0.5; } return ( <form> <MyInput placeholder="Enter your name" ref={ref} /> <button type="button" onClick={handleClick}> Edit </button> </form> ); }
公开您自己的命令式方法
通过命令式句柄公开的方法不必完全匹配 DOM 方法。例如,此Post
组件通过命令式句柄公开scrollAndFocusAddComment
方法。这允许父Page
在您单击按钮时滚动评论列表 *并* 将焦点放在输入字段上。
import { useRef } from 'react'; import Post from './Post.js'; export default function Page() { const postRef = useRef(null); function handleClick() { postRef.current.scrollAndFocusAddComment(); } return ( <> <button onClick={handleClick}> Write a comment </button> <Post ref={postRef} /> </> ); }