Как интегрировать компонент с внешней валидацией в React?
Что проверяют
Умеете ли вы связать три вещи: состояние формы, правила валидации, которые живут отдельно от компонента, и сторонний UI-компонент, который про вашу форму ничего не знает. Следом обычно спрашивают, как показать ошибку, пришедшую с сервера, и как не проверять форму на каждое нажатие клавиши.
Как отвечать
Сначала уточните, что значит «внешняя»: схема в отдельной библиотеке, проверка на сервере или готовый компонент из UI-кита. Сильный ответ покрывает все три случая.
- схема отдельно от разметки: правила описываются в Zod, Yup или Valibot, а форма подключает их через резолвер, например
zodResolverиз@hookform/resolvers. У Zod есть бонус: тип данных формы выводится из схемы черезz.infer, и та же схема проверяет данные на сервере; - сторонний компонент: обычные
inputрегистрируются черезregister, а контролируемые компоненты вродеDatePickerилиSelectоборачиваются вControllerили хукuseController. Он отдаётvalue,onChange,onBlurиref, их все и нужно пробросить; - ошибки сервера: ответ разбирается по полям и выставляется через
setError('email', { message }), общая ошибка формы черезsetError('root.server', ...); - асинхронная проверка: например, не занят ли логин. Её запускают по
onBlurили с debounce, а устаревший запрос отменяют; - режим:
mode: 'onTouched'показывает ошибку после ухода с поля, а не раньше, чем человек начал вводить.
Без библиотек каркас тот же: состояние значений, объект ошибок и функция validate, которая вызывается на blur и submit. В React 19 с Server Actions проверку повторяют на сервере и возвращают ошибки через useActionState.
Где спотыкаются
Проверяют только на клиенте. Запрос можно отправить в обход формы, поэтому серверная валидация обязательна, а клиентская нужна для удобства.
Пробрасывают в сторонний компонент только value и onChange. Без onBlur не работает режим onTouched, без ref не срабатывает фокус на первом поле с ошибкой.
Ловят исключение из validate в Yup и показывают error.message. По умолчанию abortEarly включён, и вы увидите только первую ошибку, а не все поля сразу.