Что происходит при быстром вводе нескольких символов в input в React
Что проверяют
Понимаете ли вы, как управляемое поле связано с состоянием, и отличаете ли настоящую проблему от выдуманной. Быстрый ввод сам по себе React не ломает, ломает его тяжёлая работа, повешенная на каждое нажатие.
Как отвечать
Опишите цепочку: нажатие порождает событие, onChange пишет значение в состояние, компонент перерисовывается, и в поле попадает значение из состояния. Обновления внутри одного обработчика React объединяет в один проход, но разные нажатия это разные события, то есть отдельные рендеры. Пока рендер дешёвый, пользователь ничего не замечает.
Проблемы появляются, когда на каждый символ висит фильтрация большого списка или запрос. Рецепт делится на три части:
- значение поля держите в состоянии как есть, без задержки, иначе поле начнёт отставать от клавиатуры;
- откладывайте не ввод, а следствие: запрос дебаунсите, тяжёлый список стройте от отложенного значения через
useDeferredValueили пометьте обновление несрочным черезstartTransition; - гонку ответов закрывайте отменой через
AbortControllerв очистке эффекта, иначе ответ на короткую строку придёт последним и перезапишет список.
Добавьте, что неуправляемое поле со ссылкой и чтением значения при отправке снимает вопрос целиком, когда промежуточное значение никому не нужно.
Где спотыкаются
Дебаунсят само значение поля. Ввод начинает дёргаться, а курсор прыгает в конец строки: пока задержка не истекла, в атрибуте значения лежит старый текст, и React возвращает его в поле поверх набранного.
Читают значение из объекта события асинхронно, внутри таймера или после await. Значение снимают сразу, в первой строке обработчика, и дальше работают с переменной.
Лечат тормоза мемоизацией обработчика. Обёртка вокруг onChange не ускоряет ничего, если на каждый ввод перерисовывается тяжёлое поддерево. Мемоизировать надо то, что зависит от значения, а не функцию, которая его записывает.