useImperativeHandle 是一个 React Hook,它可以让你自定义作为 ref. 暴露出去的句柄。
useImperativeHandle(ref, createHandle, dependencies?)参考
useImperativeHandle(ref, createHandle, dependencies?)
在组件顶层调用 useImperativeHandle,以自定义它所暴露的 ref 句柄:
import { useImperativeHandle } from 'react';
function MyInput({ ref }) {
useImperativeHandle(ref, () => {
return {
// ... 你的方法 ...
};
}, []);
// ...参数
-
ref:你作为 props 从MyInput组件中接收到的ref。 -
createHandle:一个不接受参数并返回你想要暴露的 ref 句柄的函数。该 ref 句柄可以是任何类型。通常,你会返回一个包含你想要暴露的方法的对象。 -
可选
dependencies:createHandle代码内部引用的所有响应式值列表。响应式值包括 props、state,以及直接在组件函数体内声明的所有变量和函数。如果你的 linter 已为 React 配置,它会验证每个响应式值都被正确地指定为依赖项。依赖项列表必须包含固定数量的项,并且要内联写成[dep1, dep2, dep3]这样的形式。React 会使用Object.is比较来对比每个依赖项与其之前的值。如果一次重新渲染导致某个依赖项发生变化,或者你省略了这个参数,你的createHandle函数将会重新执行,并且新创建的句柄会被赋值给 ref。
返回值
useImperativeHandle 返回 undefined。
用法
向父组件暴露自定义的 ref 句柄
要向父元素暴露一个 DOM 节点,请将 ref prop 传给该节点。
function MyInput({ ref }) {
return <input ref={ref} />;
};使用上面的代码时,MyInput 的 ref 将接收到 <input> DOM 节点。 不过,你也可以改为暴露一个自定义值。要自定义暴露的句柄,请在组件顶层调用 useImperativeHandle:
import { useImperativeHandle } from 'react';
function MyInput({ ref }) {
useImperativeHandle(ref, () => {
return {
// ... 你的方法 ...
};
}, []);
return <input />;
};注意,在上面的代码中,ref 不再传给 <input>。
例如,假设你不想暴露整个 <input> DOM 节点,而是想暴露它的两个方法:focus 和 scrollIntoView。为此,将真实的浏览器 DOM 保存在一个单独的 ref 中。然后使用 useImperativeHandle 来暴露一个只包含你希望父组件调用的方法的句柄:
import { useRef, useImperativeHandle } from 'react';
function MyInput({ ref }) {
const inputRef = useRef(null);
useImperativeHandle(ref, () => {
return {
focus() {
inputRef.current.focus();
},
scrollIntoView() {
inputRef.current.scrollIntoView();
},
};
}, []);
return <input 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(); // 这不会起作用,因为 DOM 节点没有被暴露出来: // 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} /> </> ); }