useImperativeHandle

useImperativeHandle 是一个 React 钩子,可让你自定义公开为 引用 的句柄。

¥useImperativeHandle is a React Hook that lets you customize the handle exposed as a ref.

useImperativeHandle(ref, createHandle, dependencies?)

参考

¥Reference

useImperativeHandle(ref, createHandle, dependencies?)

在组件的顶层调用 useImperativeHandle 以自定义它公开的引用句柄:

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

import { forwardRef, useImperativeHandle } from 'react';

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

请参阅下面的更多示例。

¥See more examples below.

参数

¥Parameters

  • ref:你收到的 ref 作为 forwardRef 渲染函数。 的第二个参数

    ¥ref: The ref you received as the second argument from the forwardRef render function.

  • createHandle:一个不带参数并返回要公开的引用句柄的函数。该引用句柄可以具有任何类型。通常,你将返回一个包含你想要公开的方法的对象。

    ¥createHandle: A function that takes no arguments and returns the ref handle you want to expose. That ref handle can have any type. Usually, you will return an object with the methods you want to expose.

  • 可选 dependenciescreateHandle 代码中引用的所有反应值的列表。反应值包括属性、状态以及直接在组件主体内声明的所有变量和函数。如果你的 linter 是 为 React 配置,它将验证每个反应值是否正确指定为依赖。依赖列表必须具有恒定数量的条目,并且像 [dep1, dep2, dep3] 一样写成内联。React 将使用 Object.is 比较将每个依赖与其先前的值进行比较。如果重新渲染导致某些依赖发生更改,或者如果你省略了此参数,则你的 createHandle 函数将重新执行,并且新创建的句柄将分配给引用。

    ¥optional dependencies: The list of all reactive values referenced inside of the createHandle code. Reactive values include props, state, and all the variables and functions declared directly inside your component body. If your linter is configured for React, it will verify that every reactive value is correctly specified as a dependency. The list of dependencies must have a constant number of items and be written inline like [dep1, dep2, dep3]. React will compare each dependency with its previous value using the Object.is comparison. If a re-render resulted in a change to some dependency, or if you omitted this argument, your createHandle function will re-execute, and the newly created handle will be assigned to the ref.

返回

¥Returns

useImperativeHandle 返回 undefined

¥useImperativeHandle returns undefined.


用法

¥Usage

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

¥Exposing a custom ref handle to the parent component

默认情况下,组件不会将它们的 DOM 节点暴露给父组件。比如你想让 MyInput有访问权 的父组件到 <input> 的 DOM 节点,就得用 forwardRef 来 opt in

¥By default, components don’t expose their DOM nodes to parent components. For example, if you want the parent component of MyInput to have access to the <input> DOM node, you have to opt in with forwardRef:

import { forwardRef } from 'react';

const MyInput = forwardRef(function MyInput(props, ref) {
return <input {...props} 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 { forwardRef, useImperativeHandle } from 'react';

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

return <input {...props} />;
});

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

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

例如,假设你不想公开整个 <input> DOM 节点,但想公开它的两个方法:focusscrollIntoView。为此,请将真实的浏览器 DOM 保存在单独的引用中。然后使用 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 { 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 的引用,它将能够调用其上的 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} />
    </>
  );
}

易犯错误

不要过度使用参考文献。你应该只将引用用于你不能表达为属性的命令式行为:例如,滚动到一个节点、聚焦一个节点、触发动画、选择文本等等。

¥Do not overuse refs. You should only use refs for imperative behaviors that you can’t express as props: for example, scrolling to a node, focusing a node, triggering an animation, selecting text, and so on.

如果你可以用属性来表达某些东西,你不应该使用引用。例如,与其从 Modal 组件中暴露 { open, close } 这样的命令式句柄,不如像 <Modal isOpen={isOpen} /> 那样将 isOpen 作为属性。副作用 可以帮助你通过属性暴露命令式行为。

¥If you can express something as a prop, you should not use a ref. For example, instead of exposing an imperative handle like { open, close } from a Modal component, it is better to take isOpen as a prop like <Modal isOpen={isOpen} />. Effects can help you expose imperative behaviors via props.


React 中文网 - 粤ICP备13048890号