React Hook Form — validation, error xabarlar
Muammodan boshlaylik
Brauzerning o'z validatsiyasi (HTML kursi, 19-dars) yaxshi, lekin:
- Xato xabarlari brauzer tilida va uslubida — dizayn bilan mos emas, ko'pincha inglizcha
- Xabar bir necha soniyada yo'qoladi
- "Parollar mos kelsin", "bu login band emasmi?" kabi qoidalarni yozib bo'lmaydi
- Barcha xatolarni birdaniga ko'rsatib bo'lmaydi
React Hook Form validatsiya qoidalarini register ning ikkinchi argumentida qabul qiladi va xatolarni formState.errors da beradi — ularni o'zingiz xohlagan ko'rinishda chiqarasiz.
Qoidalar
<input
{...register('ism', {
required: 'Ismni kiriting',
minLength: { value: 2, message: 'Kamida 2 ta harf' },
maxLength: { value: 50, message: "Ko'pi bilan 50 ta harf" },
})}
/>
| Qoida | Qiymat | Misol |
|---|---|---|
required |
true yoki xabar |
required: 'Majburiy maydon' |
minLength / maxLength |
{ value, message } |
minLength: { value: 8, message: '...' } |
min / max |
{ value, message } |
min: { value: 18, message: '18 yoshdan katta' } |
pattern |
{ value: RegExp, message } |
pattern: { value: /^\+998\d{9}$/, message: '...' } |
validate |
Funksiya yoki funksiyalar obyekti | Pastda |
Qisqa yozuv: minLength: 8 — xabarsiz (xato bo'ladi, lekin message bo'sh).
Xatolarni ko'rsatish
function Royxat() {
const {
register,
handleSubmit,
formState: { errors },
} = useForm();
return (
<form onSubmit={handleSubmit(console.log)} noValidate>
<label htmlFor="email">Email</label>
<input
id="email"
type="email"
aria-invalid={errors.email ? 'true' : 'false'}
aria-describedby={errors.email ? 'email-xato' : undefined}
{...register('email', {
required: 'Emailni kiriting',
pattern: {
value: /^[^\s@]+@[^\s@]+\.[^\s@]+$/,
message: "Email formati noto'g'ri",
},
})}
/>
{errors.email && (
<p id="email-xato" role="alert" className="xato">
{errors.email.message}
</p>
)}
<button type="submit">Yuborish</button>
</form>
);
}
errors.email— xato bo'lsa obyekt:{ type: 'required', message: 'Emailni kiriting' }noValidate— brauzerning o'z xabarlarini o'chiradi; endi faqat sizning xabarlaringizaria-invalidvaaria-describedby— ekran o'quvchi "Email, noto'g'ri, Emailni kiriting" deb o'qiydi (HTML kursi, 21-dars)role="alert"— xato paydo bo'lganda darhol o'qiladi
Qayta ishlatiladigan maydon komponenti
Har bir maydon uchun bir xil kodni takrorlamaslik uchun:
import { cloneElement } from 'react';
function Maydon({ label, name, xato, children }) {
const xatoId = `${name}-xato`;
return (
<div className="maydon">
<label htmlFor={name}>{label}</label>
{cloneElement(children, {
id: name,
'aria-invalid': xato ? 'true' : 'false',
'aria-describedby': xato ? xatoId : undefined,
})}
{xato && <p id={xatoId} role="alert">{xato.message}</p>}
</div>
);
}
<Maydon label="Ism" name="ism" xato={errors.ism}>
<input {...register('ism', { required: 'Ismni kiriting' })} />
</Maydon>
validate — o'z qoidangiz
<input
{...register('login', {
required: 'Loginni kiriting',
validate: (qiymat) =>
!qiymat.includes(' ') || "Login da bo'sh joy bo'lmasin",
})}
/>
validate funksiyasi:
trueqaytarsa — to'g'ri- string qaytarsa — shu xabar bilan xato
falseqaytarsa — xabarsiz xato
Bir nechta qoida
{...register('parol', {
required: 'Parolni kiriting',
validate: {
uzunlik: (v) => v.length >= 8 || 'Kamida 8 belgi',
raqam: (v) => /\d/.test(v) || 'Kamida bitta raqam',
katta: (v) => /[A-Z]/.test(v) || 'Kamida bitta katta harf',
},
})}
errors.parol.type — qaysi qoida buzilgani: 'raqam', 'katta'...
Boshqa maydonga bog'liq qoida
const { register, getValues } = useForm();
<input type="password" {...register('parol', { required: true })} />
<input
type="password"
{...register('parolTakror', {
required: 'Parolni takrorlang',
validate: (v) => v === getValues('parol') || 'Parollar mos kelmadi',
})}
/>
Async — server tekshiruvi
{...register('login', {
validate: async (login) => {
const j = await fetch(`/api/login-bandmi?login=${encodeURIComponent(login)}`);
const { band } = await j.json();
return !band || 'Bu login band';
},
})}
Async validate har tekshiruvda so'rov yuboradi — mode bilan birga ehtiyot bo'lib ishlating (pastda).
mode — qachon tekshirish
const { register } = useForm({
mode: 'onTouched',
reValidateMode: 'onChange',
});
mode |
Qachon tekshiradi | Foydalanuvchi tajribasi |
|---|---|---|
onSubmit (standart) |
Faqat yuborishda | Kam bezovta, lekin xato kech ko'rinadi |
onBlur |
Maydondan chiqqanda | Yaxshi muvozanat |
onTouched |
Birinchi blur dan keyin, keyin har o'zgarishda | Ko'p hollarda eng yaxshi |
onChange |
Har harfda | Bezovta qiladi — yozib bo'lmay turib "noto'g'ri!" |
all |
Blur va change | — |
reValidateMode — yuborishga urinishdan keyin qachon qayta tekshirish (standart — onChange: foydalanuvchi xatoni tuzatayotganda xabar darhol yo'qoladi).
[!TIP] Foydalanuvchi yozib bo'lmasdan turib xato ko'rsatmang.
onTouched— maydondan birinchi marta chiqqandan keyin tekshiradi, keyin esa tuzatish jarayonida xato darhol yo'qoladi. Bu HTML dagi:user-invalid(HTML kursi, 19-dars) ning xatti-harakatiga o'xshaydi.
Server xatolari — setError
Server javob berdi: "Bu email bilan foydalanuvchi allaqachon mavjud". Xatoni tegishli maydon yonida ko'rsatish:
const { register, handleSubmit, setError, formState: { errors } } = useForm();
async function onSubmit(data) {
const j = await fetch('/api/royxat', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data),
});
if (j.status === 409) {
setError('email', { type: 'server', message: "Bu email allaqachon ro'yxatdan o'tgan" });
return;
}
if (!j.ok) {
setError('root.server', { message: "Server xatosi. Keyinroq urinib ko'ring." });
}
}
{errors.root?.server && <p role="alert">{errors.root.server.message}</p>}
setError('maydon', ...)— aniq maydonga xatosetError('root.nimadir', ...)— butun formaga tegishli xatoclearErrors()— xatolarni tozalash
Muammo: qoidalar JSX ichida
Katta formada qoidalar JSX bo'ylab tarqalib ketadi: ularni qayta ishlatib, testlab, server bilan bo'lishib bo'lmaydi. TypeScript da forma turi va qoidalar alohida yoziladi va bir-biridan farq qilib qolishi mumkin.
Yechim — barcha qoidalarni bitta sxema da yozish. Keyingi dars — Zod.
Nima uchun shunday?
Nima uchun xatolarni foydalanuvchi maydondan chiqqandan keyin ko'rsatish (onTouched) — darhol (onChange) dan yaxshiroq?
Chunki foydalanuvchi hali yozib bo'lmagan. Email maydoniga a harfini yozishi bilan "Email formati noto'g'ri" deyish — xuddi gapirayotgan odamning gapini birinchi so'zidayoq "noto'g'ri!" deb bo'lishga o'xshaydi. Tadqiqotlar shuni ko'rsatadiki, bunday "erta" xatolar foydalanuvchini asabiylashtiradi va formani tugatish ehtimolini kamaytiradi. Boshqa tomondan, faqat yuborishda tekshirish ham yomon: foydalanuvchi 12 ta maydonni to'ldirib, keyin 5 ta xatoni birdaniga ko'radi. onTouched — o'rta yo'l: maydon tugatilgandan keyin baholanadi, va xato tuzatilayotganda darhol yo'qoladi — ijobiy fikr-mulohaza tez, salbiy esa o'z vaqtida.
Xulosa
Eslab qoling:
- Qoidalar —
register('nom', { required, minLength, maxLength, min, max, pattern, validate }) - Xabar bilan:
{ value, message }yokirequired: 'Xabar' errors.nom?.message— xato matni;noValidate— brauzer xabarlari o'chiriladi- Accessibility:
aria-invalid,aria-describedby,role="alert" validate—trueyoki xabar string; bir nechta qoida — obyekt; async ham mumkin- Bog'liq maydonlar —
getValues('parol') mode: 'onTouched'— ko'p hollarda eng yaxshi- Server xatolari —
setError('maydon')yokisetError('root.server')
Keyingi dars
65-dars: React Hook Form — Zod bilan schema validation