HOW TO React

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.

On this page