HTML-инпуты формируют базовый слой пользовательского ввода, вокруг
которого строится вся модель состояния формы в связке с React Hook Form
и резолвером схемы валидации Yup. Основная идея интеграции заключается в
том, что нативные элементы DOM остаются источником истины для
пользовательского ввода, а библиотека управления формой лишь
подписывается на их изменения через ref и события.
В React Hook Form нативные input-элементы подключаются через
register, который создаёт мост между DOM и системой
валидации.
import { useForm } from "react-hook-form";
import { yupResolver } from "@hookform/resolvers/yup";
Регистрация обеспечивает:
Пример базовой регистрации:
const { register, handleSubmit } = useForm({
resolver: yupResolver(schema),
});
<input type="text" {...register("username")} />
Нативный input остаётся uncontrolled, а его состояние извлекается через ref.
YupResolver выполняет промежуточную трансформацию между значениями формы и схемой валидации Yup. При каждом сабмите или триггере валидации происходит:
const schema = yup.object({
username: yup.string().required(),
});
Ключевой момент заключается в том, что нативный input не знает о правилах валидации, вся логика изолирована в resolver.
Нативный input type="text" возвращает строку независимо
от ожидаемого типа. При использовании YupResolver часто возникает
необходимость преобразования типов.
age: yup.number().transform((value) => Number(value))
Важно учитывать, что DOM всегда возвращает string.
Checkbox имеет особую модель данных: checked вместо
value.
<input type="checkbox" {...register("isActive")} />
Yup-схема:
isActive: yup.boolean()
React Hook Form автоматически маппит checked в
boolean.
Radio buttons группируются по имени поля, а значение определяется выбранным input.
<input type="radio" value="male" {...register("gender")} />
<input type="radio" value="female" {...register("gender")} />
Yup:
gender: yup.string().oneOf(["male", "female"])
Select элемент возвращает строковое значение выбранного option.
<select {...register("country")}>
<option value="kz">Kazakhstan</option>
<option value="ru">Russia</option>
</select>
При необходимости преобразования типов используется transform в Yup.
File input не сериализуется в строку и требует отдельной обработки:
<input type="file" {...register("avatar")} />
Yup-схема:
avatar: yup
.mixed()
.test("fileSize", "File too large", (file) => {
return file && file[0]?.size < 2000000;
});
Нативные input элементы опираются на defaultValue и
defaultChecked при инициализации.
useForm({
defaultValues: {
username: "",
isActive: false,
},
});
При использовании YupResolver важно, чтобы defaultValues соответствовали типам схемы, иначе возможны расхождения между initial state и validation schema.
Ошибки, возвращаемые YupResolver, привязываются к конкретным полям
через formState.errors.
const {
register,
formState: { errors },
} = useForm({
resolver: yupResolver(schema),
});
Отображение ошибки рядом с input:
<input {...register("username")} />
<p>{errors.username?.message}</p>
Каждый нативный input остаётся неизменным, а ошибки накладываются поверх DOM-структуры.
Нативные input работают в режиме uncontrolled, что даёт:
Изменения фиксируются через event listeners, а не через
onChange state-binding.
Нативные input поддерживают вложенные структуры через dot notation:
<input {...register("profile.firstName")} />
<input {...register("profile.lastName")} />
Yup schema:
profile: yup.object({
firstName: yup.string().required(),
lastName: yup.string().required(),
});
React Hook Form автоматически формирует вложенный объект из плоских DOM значений.
Массивы реализуются через индексированные имена:
<input {...register("items.0.name")} />
<input {...register("items.1.name")} />
Yup:
items: yup.array().of(
yup.object({
name: yup.string().required(),
})
);
Нативные input не знают о структуре массива — она формируется на уровне формы.
При каждом submit происходит:
Это означает, что нативные input не участвуют в валидации напрямую и остаются изолированными от бизнес-логики.
Использование нативных input в связке с React Hook Form и YupResolver снижает количество операций:
Особенно заметно это при большом количестве полей (50+), где controlled inputs приводят к деградации производительности.
Нативные input работают через стандартные DOM события:
React Hook Form подписывается на них через ref, а YupResolver
срабатывает только при необходимости, а не на каждый keystroke, если не
включён режим mode: "onChange".
Расхождение типов между DOM и Yup schema:
Некорректная инициализация defaultValues:
Неправильная обработка file input:
Нативные input элементы формируют слой ввода, React Hook Form управляет регистрацией и жизненным циклом данных, а YupResolver выполняет централизованную валидацию без вмешательства в DOM. Такая архитектура разделяет ответственность: HTML отвечает за ввод, форма за состояние, схема за правила данных.