Нужно ли использовать useEffect для подписки на изменения неконтролируемого input с ref в React?
Что проверяют
Понимаете ли вы, зачем поле делают неконтролируемым, и не возвращаете ли окольным путём то, от чего ушли. Плюс базовая гигиена эффектов: подписка, очистка, зависимости.
Как отвечать
По умолчанию нет. Смысл неконтролируемого поля в том, что значение живёт в DOM и ввод не перерисовывает дерево на каждый символ. Если вы подписываетесь на событие и кладёте значение в состояние, вы получили контролируемое поле худшим способом: с двумя источниками правды и лишним слоем.
Что делать вместо этого:
- значение нужно только при отправке: прочитать
ref.current.valueв обработчике submit или собрать форму черезFormData; - нужна реакция на ввод: повесить
onChangeпрямо на элемент, он прекрасно сочетается сrefиdefaultValueи никакого эффекта не требует; - нужно состояние на каждый символ: это уже контролируемое поле, признайте честно.
const ref = useRef(null);
<input ref={ref} defaultValue="" onChange={(e) => validate(e.target.value)} />Эффект оправдан, когда источник событий вне React: чужой виджет, узел, отрендеренный не React, глобальные события окна. Правила тогда обычные: подписка и отписка в одном эффекте, узел сохранён в локальную переменную внутри эффекта, а не прочитан из ссылки в момент очистки.
Где спотыкаются
Пишут эффект без списка зависимостей, который читает поле и кладёт значение в состояние. Обновление состояния вызывает рендер, рендер запускает эффект снова, получается бесконечный цикл.
Снимают слушатель не с того узла. В функции очистки обращаются к ref.current напрямую, а он к этому моменту уже другой или null, и обработчик остаётся висеть на старом элементе.
Смешивают value и defaultValue. Подставляют value без onChange, поле перестаёт принимать ввод, а React пишет предупреждение о переходе между контролируемым и неконтролируемым состоянием.