Что такое forwardRef в React и для чего он используется?
Что проверяют
Понимаете ли вы, что ref в React живёт отдельно от пропсов, и умеете ли строить переиспользуемые компоненты, которые не прячут от родителя настоящий DOM-узел. Вопрос почти всегда ведёт к дизайн-системе: обёртки над полями ввода и кнопками без прокинутого рефа ломают фокус, скролл и интеграцию с внешними библиотеками.
Как отвечать
ref и key не попадают в объект пропсов, поэтому раньше функциональный компонент их просто не видел: рассыпание {...props} реф не переносило. forwardRef оборачивал компонент так, что реф приходил вторым аргументом, и его можно было повесить на нужный узел внутри.
const Field = forwardRef(function Field(props, ref) {
return <input ref={ref} {...props} />;
});Важное уточнение: в современном React реф стал обычным пропом функционального компонента, forwardRef для нового кода не нужен и помечен как устаревший, для миграции есть кодмод.
function Field({ ref, ...props }) {
return <input ref={ref} {...props} />;
}Отдельно стоит назвать useImperativeHandle: он отдаёт наружу не голый узел, а ограниченный набор методов вроде фокуса или прокрутки к элементу. Это правильный ответ на вопрос, зачем вообще пускать родителя внутрь: императивный доступ оставляют для фокуса, измерений, медиаэлементов и чужих виджетов, всё остальное делается пропсами и состоянием.
Где спотыкаются
Ждут, что через реф откроется внутреннее состояние компонента. Наружу видно ровно то, к чему привязан узел или что перечислено в useImperativeHandle, остальное недоступно, и попытка дёрнуть чужой сеттер через реф это сигнал неверной декомпозиции.
Рассыпают пропсы и уверены, что реф уедет вместе с ними. Он не проп, в объекте его нет, и молчаливое последствие такое: родитель получает null и ничего не падает, просто фокус не срабатывает.
Читают значение рефа во время рендера. На первом рендере узла ещё нет, поле заполняется после монтирования, поэтому обращаться к нему можно в эффекте или обработчике. Туда же относится реф на условно отрендеренный элемент: при размонтировании React кладёт null, и обработчик обязан это переживать.