Что такое useImperativeHandle

Ответ

useImperativeHandle — это хук React, который позволяет кастомизировать экземпляр компонента, доступный через ref. Он полезен, когда родительскому компоненту нужно напрямую вызывать методы дочернего компонента.

Пример:

import { forwardRef, useImperativeHandle, useRef } from 'react';

const ChildComponent = forwardRef((props, ref) => {
  const inputRef = useRef();

  useImperativeHandle(ref, () => ({
    focus: () => inputRef.current.focus(),
    clear: () => (inputRef.current.value = ''),
  }));

  return <input ref={inputRef} />;
});

function ParentComponent() {
  const childRef = useRef();

  return (
    <>
      <ChildComponent ref={childRef} />
      <button onClick={() => childRef.current.focus()}>Focus</button>
      <button onClick={() => childRef.current.clear()}>Clear</button>
    </>
  );
}

Нюансы:

  • Работает только с forwardRef.
  • Не злоупотребляйте им — нарушает инкапсуляцию.
  • Альтернатива — подъем состояния или колбэки.

Ответ 18+ 🔞

Слушай, ну вот есть же такие ситуации в React, когда тебе реально нужно, чтобы родительский компонент мог напрямую что-то сделать с дочерним. Не через пропсы туда-сюда состояние гонять, а прям ручками, по-быстрому. Вот для этого, блядь, и придумали useImperativeHandle.

Представь себе: у тебя есть дочерний компонент с инпутом, и ты хочешь, чтобы по кнопке в родителе этот инпут фокусировался или очищался. Ну, чтобы не городить огород. Вот как это выглядит, ёпта:

import { forwardRef, useImperativeHandle, useRef } from 'react';

const ChildComponent = forwardRef((props, ref) => {
  const inputRef = useRef();

  useImperativeHandle(ref, () => ({
    focus: () => inputRef.current.focus(),
    clear: () => (inputRef.current.value = ''),
  }));

  return <input ref={inputRef} />;
});

function ParentComponent() {
  const childRef = useRef();

  return (
    <>
      <ChildComponent ref={childRef} />
      <button onClick={() => childRef.current.focus()}>Focus</button>
      <button onClick={() => childRef.current.clear()}>Clear</button>
    </>
  );
}

Видишь? Родитель теперь может через childRef.current вызывать методы focus и clear, которые мы, сука, наэкспортируем наружу из дочернего компонента. Удобно же, в рот меня чих-пых!

Но, внимание, нюансы, ёбана!

  • Эта штука работает ТОЛЬКО в паре с forwardRef. Без него — нихуя не выйдет, просто ошибку получишь.
  • Не начинай им везде пользоваться, как полудурок! Это нарушает инкапсуляцию, блядь. React и так намекает, что данные должны течь вниз. Если можно решить через подъём состояния или колбэки — лучше так и сделай. А то потом разберёшься в этом коде через месяц и сам себе скажешь: «Какой же я был мудак, блядь...».
  • Это как мощный инструмент — им можно и гвоздь забить, и себе по пальцам въебать. Используй точечно, где реально нужно.