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 виконуватиметься повторно, і новостворений дескриптор буде призначений рефу.

Note

Починаючи з React 19 реф доступний як проп. У React 18 і старіших версіях необхідно було отримувати реф з forwardRef.

Результат

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

Pitfall

Не зловживайте рефами. Використовуйте рефи лише для імперативної поведінки, яку ви не можете виразити через пропси: наприклад, прогортування до вузла DOM, фокусування вузла, виклик анімації, виділення тексту тощо.

Якщо ви можете виразити щось як проп, тоді не варто використовувати реф. Наприклад, замість передавання імперативного дескриптора як { open, close } із компонента Modal, краще використати проп isOpen як <Modal isOpen={isOpen} />. Ефекти можуть допомогти вам надати доступ до імперативних частин через пропси.