Как useRef используется с useImperativeHandle?
Хуки
Связка useRef + useImperativeHandle позволяет родителю дёргать методы дочернего компонента: ребёнок публикует наружу ограниченный императивный API вместо сырого DOM-узла.
Роли хуков
- useRef (у родителя) — создаёт «розетку»: контейнер, куда попадёт API ребёнка.
- useImperativeHandle (у ребёнка) — определяет, ЧТО именно окажется в этом ref: вместо DOM-узла — объект с методами.
Пример
// Ребёнок: кастомный инпут с публичным API
const FancyInput = forwardRef(function FancyInput(props, ref) {
const inputRef = useRef(null); // внутренний ref на настоящий DOM
useImperativeHandle(ref, () => ({
focus: () => inputRef.current.focus(),
clear: () => { inputRef.current.value = ''; },
// сырой DOM-узел наружу НЕ отдаём
}), []);
return <input ref={inputRef} {...props} />;
});
// Родитель: пользуется API
const Form = () => {
const fancyRef = useRef(null); // сюда попадёт { focus, clear }
const handleReset = () => {
fancyRef.current.clear();
fancyRef.current.focus();
};
return (
<>
<FancyInput ref={fancyRef} />
<button onClick={handleReset}>Сброс</button>
</>
);
};До React 19 ребёнку нужен forwardRef (ref — не проп); в React 19 ref приходит обычным пропом, useImperativeHandle работает так же.
Зачем это нужно
- Инкапсуляция: родитель получает контракт (focus/clear), а не внутренности; внутреннюю разметку можно менять свободно.
- Типичные кейсы: методы форм (reset, validate), управление плеером (play/pause), скролл списка к элементу (scrollToItem), открытие/закрытие модалки.
Использовать умеренно: императивный API — исключение; всё, что можно, выражается декларативно через props.
Коротко для собеседования
useRef у родителя — контейнер; useImperativeHandle у ребёнка (с forwardRef до React 19) кладёт в него ограниченный API ({ focus, clear }) вместо DOM-узла. Родитель вызывает методы императивно. Применять точечно: фокус, reset форм, управление плеером/скроллом — остальное декларативно.