useImperativeHandle

useImperativeHandle 是一个 React Hook,它允许你自定义作为 ref. 暴露的句柄

useImperativeHandle(ref, createHandle, dependencies?)

参考

🌐 Reference

useImperativeHandle(ref, createHandle, dependencies?)

在组件的顶层调用 useImperativeHandle 来自定义它暴露的 ref 句柄:

🌐 Call useImperativeHandle at the top level of your component to customize the ref handle it exposes:

import { useImperativeHandle } from 'react';

function MyInput({ ref }) {
useImperativeHandle(ref, () => {
return {
// ... your methods ...
};
}, []);
// ...

查看更多示例。

参数

🌐 Parameters

  • refMyInput 组件接收到的 ref 属性。
  • createHandle:一个不带参数并返回你想要公开的引用句柄的函数。该引用句柄可以是任何类型。通常,你会返回一个包含你想要公开的方法的对象。
  • 可选 dependencies:在 createHandle 代码中引用的所有响应式值的列表。响应式值包括 props、state,以及直接在组件体内声明的所有变量和函数。如果你的 linter 为 React 配置 ,它将验证每个响应式值是否已正确指定为依赖。依赖列表必须有固定数量的项目,并且像 [dep1, dep2, dep3] 一样以内联形式书写。React 将使用 Object.is 比较将每个依赖与之前的值进行比较。如果重新渲染导致某些依赖发生变化,或者你省略了该参数,你的 createHandle 函数将重新执行,并且新创建的句柄将分配给 ref。

注意

从 React 19 开始,ref 可作为 prop 使用。 在 React 18 及更早版本中,需要从 forwardRef 获取 ref

🌐 Starting with React 19, ref is available as a prop. In React 18 and earlier, it was necessary to get the ref from forwardRef.

返回

🌐 Returns

useImperativeHandle 返回 undefined


用法

🌐 Usage

向父组件公开自定义引用句柄

🌐 Exposing a custom ref handle to the parent component

要将 DOM 节点暴露给父元素,请将 ref 属性传入该节点。

🌐 To expose a DOM node to the parent element, pass in the ref prop to the node.

function MyInput({ ref }) {
return <input ref={ref} />;
};

使用上面的代码,MyInput 的引用将接收 <input> DOM 节点。 但是,你可以暴露一个自定义值。要自定义暴露的句柄,请在组件的顶层调用 useImperativeHandle

🌐 With the code above, a ref to MyInput will receive the <input> DOM node. However, you can expose a custom value instead. To customize the exposed handle, call useImperativeHandle at the top level of your component:

import { useImperativeHandle } from 'react';

function MyInput({ ref }) {
useImperativeHandle(ref, () => {
return {
// ... your methods ...
};
}, []);

return <input />;
};

请注意,在上面的代码中,ref 不再传递给 <input>

🌐 Note that in the code above, the ref is no longer passed to the <input>.

例如,假设你不想暴露整个 <input> DOM 节点,但你想暴露它的两个方法:focusscrollIntoView。为此,将真实的浏览器 DOM 保存在一个单独的 ref 中。然后使用 useImperativeHandle 暴露一个只包含你希望父组件调用的方法的句柄:

🌐 For example, suppose you don’t want to expose the entire <input> DOM node, but you want to expose two of its methods: focus and scrollIntoView. To do this, keep the real browser DOM in a separate ref. Then use useImperativeHandle to expose a handle with only the methods that you want the parent component to call:

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 的引用,它将能够调用其上的 focusscrollIntoView 方法。然而,它将无法完全访问底层的 <input> DOM 节点。

🌐 Now, if the parent component gets a ref to MyInput, it will be able to call the focus and scrollIntoView methods on it. However, it will not have full access to the underlying <input> DOM node.

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>
  );
}


公开你自己的命令式方法

🌐 Exposing your own imperative methods

通过命令式句柄暴露的方法不必与 DOM 方法完全匹配。例如,这个 Post 组件通过命令式句柄暴露了一个 scrollAndFocusAddComment 方法。这让父组件 Page 在点击按钮时既可以滚动评论列表,也可以聚焦输入字段:

🌐 The methods you expose via an imperative handle don’t have to match the DOM methods exactly. For example, this Post component exposes a scrollAndFocusAddComment method via an imperative handle. This lets the parent Page scroll the list of comments and focus the input field when you click the button:

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} />
    </>
  );
}

易犯错误

不要过度使用 refs。 你应当仅在无法通过 props 表达的强制性行为上使用 refs:例如,滚动到某个节点、聚焦某个节点、触发动画、选择文本等等。

如果你可以将某个东西作为 prop 来表达,就不应该使用 ref。 例如,与其从 Modal 组件中暴露像 { open, close } 这样的命令式句柄,不如将 isOpen 作为 prop 传入 <Modal isOpen={isOpen} />Effects 可以帮助你通过 props 暴露命令式行为。