useImperativeHandle
useImperativeHandle — это React-хук, позволяющий настраивать обработчик, отображаемый в виде ссылки.
Reference
useImperativeHandle(ref, createHandle, dependencies?)
Вызывайте useImperativeHandle на верхнем уровне вашего компонента, чтобы настроить handle ref, который он экспортирует:
import { useImperativeHandle } from 'react';
function MyInput({ ref }) {
useImperativeHandle(ref, () => {
return {
// ... your methods ...
};
}, []);
// ...Parameters
-
ref:ref, который вы получили как prop компонентаMyInput. -
createHandle: Функция, которая не принимает аргументов и возвращает handle ref, который вы хотите экспортировать. Этот handle может иметь любой тип. Обычно вы возвращаете объект с методами, которые хотите предоставить наружу. -
optional
dependencies: Список всех реактивных значений, на которые ссылается код внутриcreateHandle. Реактивные значения включают props, state, а также все переменные и функции, объявленные непосредственно внутри тела компонента. Если ваш linter настроен для React, он проверит, что каждое реактивное значение корректно указано как dependency. Список dependencies должен содержать постоянное количество элементов и быть записан inline, как[dep1, dep2, dep3]. React сравнит каждую dependency с её предыдущим значением, используя сравнениеObject.is. Если повторный рендер привёл к изменению одной из dependencies, или если вы опустили этот аргумент, функцияcreateHandleвыполнится заново, а newly created handle будет назначен в ref.
Начиная с React 19, ref доступен как prop. В React 18 и более ранних версиях ref нужно было получать из forwardRef.
Returns
useImperativeHandle возвращает undefined.
Usage
Экспонирование custom ref handle для родительского компонента
Чтобы передать DOM node родительскому элементу, передайте prop ref в этот node.
function MyInput({ ref }) {
return <input ref={ref} />;
};В коде выше ref для MyInput получит DOM node <input>. Однако вы можете вместо этого экспортировать custom value. Чтобы настроить экспортируемый handle, вызовите useImperativeHandle на верхнем уровне вашего компонента:
import { useImperativeHandle } from 'react';
function MyInput({ ref }) {
useImperativeHandle(ref, () => {
return {
// ... your methods ...
};
}, []);
return <input />;
};Обратите внимание, что в коде выше ref больше не передаётся в <input>.
Например, допустим, вы не хотите экспортировать весь DOM node <input>, но хотите предоставить две его методы: focus и scrollIntoView. Для этого храните настоящий browser DOM в отдельном ref. Затем используйте useImperativeHandle, чтобы экспортировать handle только с теми методами, которые родительский компонент должен вызывать:
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} />;
};Теперь, если родительский компонент получит ref на MyInput, он сможет вызывать у него методы focus и scrollIntoView. Однако у него не будет полного доступа к базовому DOM node <input>.
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>
);
}Экспонирование собственных imperative-методов
Методы, которые вы экспортируете через imperative handle, не обязаны точно совпадать с DOM-методами. Например, этот компонент Post экспортирует метод scrollAndFocusAddComment через imperative handle. Это позволяет родительскому 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} />
</>
);
}Не злоупотребляйте refs. Используйте refs только для imperative поведения, которое нельзя выразить через props: например, прокрутка к node, фокусировка node, запуск анимации, выделение текста и так далее.
Если что-то можно выразить через prop, ref использовать не следует. Например, вместо того чтобы экспортировать из компонента Modal imperative handle вроде { open, close }, лучше принимать isOpen как prop, например <Modal isOpen={isOpen} />. Effects могут помочь вам реализовать imperative-поведение через props.