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 />;
};
Зверніть увагу, що в наведеному вище коді ref
більше не передається елементу <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} /> </> ); }