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