useImperativeHandle
useImperativeHandle
— це хук, який дає змогу налаштовувати дескриптор (handle) публічно доступного рефа.
useImperativeHandle(ref, createHandle, dependencies?)
Опис
useImperativeHandle(ref, createHandle, dependencies?)
Викличте useImperativeHandle
на верхньому рівні вашого компонента, щоб налаштувати дескриптор рефа, доступного з нього:
import { useImperativeHandle } from 'react';
function MyInput({ ref }) {
useImperativeHandle(ref, () => {
return {
// ... ваші методи ...
};
}, []);
// ...
Перегляньте більше прикладів нижче.
Параметри
-
ref
:ref
, який ви отримали як проп у компонентіMyInput
. -
createHandle
: Функція, яка не приймає аргументів і повертає дескриптор рефа, до якого ви хочете надати доступ. Дескриптор може бути будь-якого типу. Зазвичай, ви повертатимете об’єкт із методами, до яких ви хочете надати доступ. -
Опційний параметр
dependencies
: Список усіх реактивних значень, на які посилається кодcreateHandle
. Реактивні значення охоплюють пропси, стан і всі змінні та функції, оголошені безпосередньо в тілі компонента. Якщо ваш лінтер налаштований для React, він перевірить, чи кожне реактивне значення вказане як залежність. Список залежностей повинен містити стале число елементів, записаних у рядок як[залежність1, залежність2, залежність3]
. React порівняє кожну залежність із своїм попереднім значенням, використовуючи функціюObject.is
. Якщо повторний рендер призвів до зміни однієї із залежностей або якщо ви пропустили даний аргумент, ваша функціяcreateHandle
виконуватиметься повторно, і новостворений дескриптор буде призначений рефу.
Результат
useImperativeHandle
повертає undefined
.
Використання
Надання кастомного об’єкта посилання батьківському компоненту
Щоб надати DOM-вузол батьківському елементу, передайте проп ref до цього вузла.
function MyInput({ ref }) {
return <input ref={ref} />;
};
У коді вище посилання до MyInput
отримає DOM вузол <input>
. Однак, замість цього ви можете передати кастомне значення. Щоб кастомізувати наданий об’єкт посилання, викличте useImperativeHandle
на верхньому рівні вашого компонента:
import { useImperativeHandle } from 'react';
function MyInput({ ref }) {
useImperativeHandle(ref, () => {
return {
// ... ваші методи ...
};
}, []);
return <input />;
};
Зверніть увагу, що в наданому вище коді реф
більше не передається до <input>
.
Наприклад, припустимо, ви не хочете використовувати весь вузол DOM <input>
, а лише два його методи: focus
і scrollIntoView
. Щоб зробити це, зберігайте справжній браузерний DOM у окремому посиланні. Потім викличте 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
, він буде здатний викликати методи focus
і scrollIntoView
в компоненті. Однак, він не буде мати повного доступу до DOM вузла <input>
.
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="Введіть ваше ім'я" ref={ref} /> <button type="button" onClick={handleClick}> Змінити </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}> Написати коментар </button> <Post ref={postRef} /> </> ); }