Как React получает данные из input
Что проверяют
Понимаете ли вы разницу между контролируемым и неконтролируемым полем и откуда React вообще берёт значение. Следом часто спрашивают, почему поле с value не даёт печатать, или как собрать большую форму без перерисовки на каждое нажатие.
Как отвечать
Сам React значение из DOM не «вытягивает». Есть два способа:
- контролируемое поле: значение живёт в состоянии,
value={name}иonChange={e => setName(e.target.value)}. Источник правды это state, и React на каждом рендере выставляет полю это значение. Удобно для валидации на лету, масок, зависимых полей; - неконтролируемое поле: значение живёт в DOM, начальное задаётся через
defaultValue(у чекбоксаdefaultChecked), а читается по требованию черезuseRefиref.current.valueили изFormDataпри отправке формы.
Важные детали поведения. onChange в React срабатывает на каждый введённый символ, как нативное событие input, а не при потере фокуса, как нативный change. e.target.value всегда строка, даже у type="number", так что число приводят сами. У чекбокса смотрят e.target.checked. С React 17 пула событий нет, объект события можно читать и в асинхронном коде.
В React 19 появились actions: <form action={fn}> передаёт в функцию FormData, useActionState хранит результат и состояние отправки, а неконтролируемые поля после успешного action сбрасываются сами. Для больших форм популярен react-hook-form: он по умолчанию работает на неконтролируемых полях и рефах, поэтому ввод не перерисовывает всю форму.
Где спотыкаются
Ставят value без onChange. Поле становится только для чтения, а React пишет предупреждение в консоль.
Инициализируют состояние как undefined, а потом кладут строку. Поле переключается из неконтролируемого в контролируемое, React предупреждает и об этом, поэтому начальное значение задают пустой строкой.
Читают состояние сразу после setName и удивляются старому значению. Обновление применится на следующем рендере, актуальное значение в этот момент есть только в e.target.value.