React forwardRef

В React forwardRef — это специальный инструмент, предназначенный для передачи ссылок (refs) от родительских компонентов к их потомкам. По сути, это передача прямой ссылки на элемент DOM внутри вашего компонента. Такая возможность крайне полезна в ситуациях, когда необходим доступ к внутреннему состоянию или свойствам DOM-элементов, содержащихся внутри компонентов высшего порядка (Higher Order Component, HOC) или функциональному компоненту.


Зачем использовать forwardRef?

Иногда бывает необходимо передать ссылку (ref) внутрь какого-то компонента, например, чтобы получить доступ к DOM-элементам или реализовать специфичное поведение (получение фокуса, измерения, работа с canvas и т.п.). Однако стандартные способы передачи ссылок работают только на уровне непосредственных родителей и детей, и если в цепочке появляются промежуточные компоненты (обычно функциональные), обычная передача рефов нарушается.

Именно здесь вступает в игру forwardRef, который решает проблему и позволяет ссылкам доходить до конечного целевого элемента, проходя сквозь промежуточные слои компонентов.

Распространённые случаи использования forwardRef:

  • Получение фокуса на полях ввода
  • Запуск анимации
  • Измерение элементов DOM
  • Интеграция с внешними библиотеками

Как работает forwardRef?

Обычно в функциональном компоненте ссылка принимается вторым аргументом, передаваемым вместе с пропсами. Чтобы сделать компонент совместимым с передачей refs, нужно обернуть его конструкцией forwardRef, которая принимает аргументами функцию самого компонента и ссылку.

Пример стандартного компонента без forwardRef:


const MyInput = (props) => <input {...props} />;

Такой компонент не поддерживает передачу ссылки дальше. Но если воспользоваться forwardRef, всё изменится:


const MyInputWithForwardRef = forwardRef((props, ref) => (
  <input ref={ref} {...props} />
));

Теперь ссылка может свободно пройти сквозь этот компонент и достичь нужного DOM-элемента.


Базовый пример

Рассмотрим простую ситуацию, когда нужно сосредоточить фокус на текстовом поле, находящимся глубоко внутри структуры компонентов.

Пример


import { forwardRef, useRef } from 'react';

const MyInput = forwardRef((props, ref) => (
  <input ref={ref} {...props} />
));

function App() {
  const inputRef = useRef();

  const focusInput = () => {
    inputRef.current.focus(); // фокусируемся на поле ввода
  };

  return (
    <div>
      <MyInput ref={inputRef} placeholder="Введите текст" />
      <button onClick={focusInput}>Получить фокус</button>
    </div>
  );
}

В этом примере:

  • MyInput объявлен с использованием forwardRef, что позволяет передавать ссылку внутрь него.
  • В компоненте App создается ссылка inputRef, которая впоследствии прикрепляется к полю ввода.
  • При нажатии на кнопку Сосредоточить фокус фокус перемещается на текстовое поле.

Важные особенности forwardRef:

  1. Необходимость обертки forwardRef: Без неё ссылки не смогут проходить через промежуточные компоненты.
  2. Обработка пользовательской ссылки: Внутри вашего компонента вы можете обработать ссылку самостоятельно, добавив дополнительную логику (например, логирование или дополнительные манипуляции над элементом).
  3. Совместимость с компонентами-классами: forwardRef отлично работает и с компонентами-классами, так как у них тоже поддерживается получение второго аргумента (ссылки).
  4. Применение для пользовательских компонентов: forwardRef полезно использовать, когда вы разрабатываете повторно используемые компоненты, которым нужны специальные возможности, такие как фокусировка или получение размера элементов.

Итог

forwardRef — это мощный инструмент, который решает важные задачи в сложных приложениях React, обеспечивая надежную передачу ссылок между компонентами. Несмотря на его полезность, старайтесь избегать злоупотребления этим механизмом и применять его осознанно там, где это действительно необходимо.

Примечание: Используйте forwardRef только тогда, когда вам действительно нужен прямой доступ к элементу DOM. Во многих случаях достаточно обычного использования пропсов и состояния.