Установить фокус на инпуте сразу в React может оказаться не так просто, как кажется. При изменении стейта, React не сразу ре-рендерит компонент, а вместо этого он складывает в очередь все изменения состояний и выполняет их разом после завершения работы обработчика событий. Из-за такого поведения могут возникнуть непредвиденные ситуации, например:
function MyComponent() {
const inputRef = useRef<HTMLInputElement>(null)
const [show, setShow] = useState(false)
return (
<div>
<button
onClick={() => {
setShow(true)
inputRef.current?.focus() // Фокус не будет работать
}}
>
Show
</button>
{show ? <input ref={inputRef} /> : null}
</div>
)
}
В примере выше фокс на инпуте не появится, из-за того что изменение стейта setShow сработает только по завершению работы обработчика события onClick.
Для решения проблемы используйте функцию flushSync, которая синхронно выполняет изменение стейта в переданном колбеке. По завершению работы flushSync DOM будет обновлен и
inputRef.current?.focus() сработает. Обновленный пример обработчика:
…
<button
onClick={() => {
flushSync(() => {
setShow(true)
})
inputRef.current?.focus()
}}
>
…
https://www.epicreact.dev/mastering-focus-management-in-react-with-flush-sync-f5b38