Какие альтернативные способы установки фокуса в React без использования useEffect
Что проверяют
Понимаете ли вы, что эффект для фокуса часто лишний: фокус это реакция на событие или на появление элемента в DOM. Следом почти всегда спрашивают про доступность, куда уходит фокус при открытии и закрытии модального окна.
Как отвечать
Разберите способы по ситуациям:
autoFocus: React сам вызываетfocus(), когда элемент монтируется. Для поля в только что открытой форме или диалоге этого достаточно;- фокус в обработчике:
inputRef.current?.focus()прямо вonClickилиonSubmit. Если элемент появляется из-заsetStateв том же обработчике, его ещё нет в DOM. Тогда обновление оборачивают вflushSyncизreact-dom, и сразу после него вызываютfocus(); - callback ref: функция в
refвызывается, когда узел подключён к DOM, поэтому подходит для условно отрисованных элементов и элементов списка. В React 19 такая функция может вернуть функцию очистки; useImperativeHandle: дочерний компонент отдаёт наружу только методfocus(), а не весь DOM-узел. В React 19refпередаётся как обычный проп,forwardRefдля новых компонентов не нужен;- нативный
<dialog>: приshowModal()браузер сам переносит фокус внутрь, держит его в окне и возвращает на прежний элемент после закрытия; useLayoutEffect: формально тоже эффект, но срабатывает до отрисовки кадра.
Главная мысль ответа: фокус ставят там, где известна причина, в обработчике или в момент появления узла, а не в эффекте, который срабатывает после каждого изменения зависимостей.
Где спотыкаются
Пишут inline callback ref вроде ref={el => el?.focus()}. На каждом рендере это новая функция, React вызывает её заново, и фокус возвращается в поле при любом обновлении. Функцию выносят из рендера или оборачивают в useCallback.
Вызывают focus() сразу после setState и не понимают, почему ничего не происходит. Элемент ещё не отрисован, нужен flushSync, callback ref или autoFocus на самом элементе.
Забывают про доступность. Убирают обводку через outline: none без замены на стиль :focus-visible, не возвращают фокус на кнопку после закрытия модалки, и пользователь с клавиатуры теряется на странице.