HTML forma bilan ishlash — onSubmit, preventDefault

~15 daq · React · Formalar

Muammodan boshlaylik

Login formasi:

function Login() {
  const [email, setEmail] = useState('');
  const [parol, setParol] = useState('');

  function kirish() {
    console.log(email, parol);
  }

  return (
    <div>
      <input value={email} onChange={(e) => setEmail(e.target.value)} />
      <input type="password" value={parol} onChange={(e) => setParol(e.target.value)} />
      <button onClick={kirish}>Kirish</button>
    </div>
  );
}

Ishlaydi... deyarli:

  • Parolni yozib Enter bosasiz — hech narsa bo'lmaydi
  • Brauzer parol menejeri parolni saqlashni taklif qilmaydi
  • Ekran o'quvchi "forma" ni ko'rmaydi
  • required, type="email" kabi brauzer tekshiruvlari ishlamaydi

Sabab: <form> yo'q. React da ham HTML formalari (HTML kursi, 15-dars) ning barcha qoidalari amal qiladi — faqat ma'lumot yuborishni biz boshqaramiz.


onSubmit va preventDefault

function Login() {
  const [email, setEmail] = useState('');
  const [parol, setParol] = useState('');

  function handleSubmit(e) {
    e.preventDefault();                 // sahifa yangilanmasin
    console.log({ email, parol });
  }

  return (
    <form onSubmit={handleSubmit}>
      <label htmlFor="email">Email</label>
      <input
        id="email"
        type="email"
        autoComplete="email"
        required
        value={email}
        onChange={(e) => setEmail(e.target.value)}
      />

      <label htmlFor="parol">Parol</label>
      <input
        id="parol"
        type="password"
        autoComplete="current-password"
        required
        minLength={8}
        value={parol}
        onChange={(e) => setParol(e.target.value)}
      />

      <button type="submit">Kirish</button>
    </form>
  );
}
  • onSubmit — <form> da, tugmada onClick emas. Tugma bosilganda ham, Enter bosilganda ham ishlaydi
  • e.preventDefault() — brauzerning standart xatti-harakatini to'xtatadi: formani action manziliga yuborish va sahifani qayta yuklash. Busiz SPA yangilanadi va butun state yo'qoladi
  • required, minLength, type="email" — brauzer tekshiruvi onSubmit dan oldin ishlaydi; xato bo'lsa handleSubmit chaqirilmaydi

JSX dagi farqlar

HTML JSX
for="email" htmlFor="email"
minlength="8" minLength={8}
autocomplete="email" autoComplete="email"
readonly readOnly
<textarea>matn</textarea> <textarea value={matn} />
<option selected> <select value={tanlangan}>

Controlled — har bir maydon state da

28-darsdagi controlled yondashuv: har bir input ning qiymati useState da, har harfda yangilanadi.

Ko'p maydonli formada har biri uchun alohida useState noqulay. Bitta obyekt bilan:

function Royxat() {
  const [forma, setForma] = useState({
    ism: '',
    email: '',
    yosh: '',
    shartlar: false,
  });

  function handleChange(e) {
    const { name, value, type, checked } = e.target;
    setForma((oldingi) => ({
      ...oldingi,
      [name]: type === 'checkbox' ? checked : value,
    }));
  }

  function handleSubmit(e) {
    e.preventDefault();
    console.log(forma);
  }

  return (
    <form onSubmit={handleSubmit}>
      <input name="ism" value={forma.ism} onChange={handleChange} />
      <input name="email" type="email" value={forma.email} onChange={handleChange} />
      <input name="yosh" type="number" value={forma.yosh} onChange={handleChange} />
      <label>
        <input name="shartlar" type="checkbox" checked={forma.shartlar} onChange={handleChange} />
        Shartlarga roziman
      </label>
      <button type="submit">Ro'yxatdan o'tish</button>
    </form>
  );
}
  • name atributi state dagi kalit bilan bir xil — bitta handleChange hammasiga yetadi
  • [name]: ... — hisoblangan kalit
  • Checkbox uchun checked, qolganlari uchun value

[!WARNING] type="number" li input ham e.target.value da string qaytaradi: "25", 25 emas. Hisob-kitobdan oldin Number(forma.yosh) qiling yoki e.target.valueAsNumber dan foydalaning.


Uncontrolled — FormData bilan

Har harfda state yangilash shart bo'lmasa — qiymatlarni faqat yuborishda olish mumkin (29-dars, uncontrolled):

function Aloqa() {
  function handleSubmit(e) {
    e.preventDefault();
    const formData = new FormData(e.currentTarget);
    const malumot = Object.fromEntries(formData);
    // { ism: 'Ali', email: 'ali@mail.uz', xabar: '...' }
    console.log(malumot);
    e.currentTarget.reset();          // formani tozalash
  }

  return (
    <form onSubmit={handleSubmit}>
      <input name="ism" required />
      <input name="email" type="email" required />
      <textarea name="xabar" required />
      <button type="submit">Yuborish</button>
    </form>
  );
}
  • State yo'q, har harfda render yo'q
  • FormData maydonlarni name bo'yicha yig'adi (HTML kursi, 15-dars)
  • Bir nechta checkbox bir xil nom bilan — formData.getAll('qiziqishlar')
Controlled Uncontrolled (FormData)
Qiymat qayerda React state DOM
Har harfda render ✅ ❌
Darhol tekshirish, formatlash (+998 __ ___) ✅ Oson Qiyin
Boshqa maydonga bog'liq UI ✅ Oson Qiyin
Kod Ko'proq Kam

Yuborish holati

function Aloqa() {
  const [holat, setHolat] = useState('idle');   // 'idle' | 'yuborilmoqda' | 'yuborildi' | 'xato'

  async function handleSubmit(e) {
    e.preventDefault();
    const form = e.currentTarget;
    setHolat('yuborilmoqda');
    try {
      const j = await fetch('/api/aloqa', {
        method: 'POST',
        body: new FormData(form),
      });
      if (!j.ok) throw new Error();
      setHolat('yuborildi');
      form.reset();
    } catch {
      setHolat('xato');
    }
  }

  if (holat === 'yuborildi') return <p>Rahmat! Xabaringiz yuborildi.</p>;

  return (
    <form onSubmit={handleSubmit}>
      <fieldset disabled={holat === 'yuborilmoqda'}>
        <input name="email" type="email" required />
        <textarea name="xabar" required />
        <button type="submit">
          {holat === 'yuborilmoqda' ? 'Yuborilmoqda...' : 'Yuborish'}
        </button>
      </fieldset>
      {holat === 'xato' && <p role="alert">Xatolik. Qaytadan urinib ko'ring.</p>}
    </form>
  );
}
  • <fieldset disabled> — yuborilayotganda barcha maydonlarni bir yo'la o'chiradi; ikki marta yuborishning oldini oladi
  • e.currentTarget ni await dan oldin o'zgaruvchiga saqlang — keyin u null bo'lishi mumkin
  • role="alert" — xato ekran o'quvchiga darhol o'qiladi

[!TIP] React 19 da <form action={funksiya}> va useActionState, useFormStatus hook lari paydo bo'ldi — ular yuborish holatini avtomatik boshqaradi va ayniqsa Server Actions (Next.js) bilan qulay. Oddiy SPA da yuqoridagi onSubmit usuli ham, React Hook Form (keyingi dars) ham to'liq mos.


Nima uchun shunday?

Nima uchun React da <form> ishlatish kerak — hamma narsani onClick va state bilan qilsa bo'ladi-ku?

Bo'ladi — lekin brauzer bepul beradigan narsalarni yo'qotasiz va ularni qo'lda qayta yozishga majbur bo'lasiz. <form> — bu shunchaki o'ram emas, brauzerga "bu maydonlar birga, bular yuboriladigan ma'lumot" degan semantik signal. Shu signal tufayli Enter bilan yuborish, parol menejerlari, avtoto'ldirish, brauzer validatsiyasi, telefonda "Keyingi/Yuborish" tugmalari va ekran o'quvchilarda forma navigatsiyasi ishlaydi. React bu mexanizmni almashtirmaydi — u faqat oxirgi qadamni (sahifa qayta yuklanishini) preventDefault bilan to'xtatib, ma'lumot yuborishni sizga topshiradi.


Xulosa

Eslab qoling:

  • Har doim <form onSubmit> — tugmada onClick emas; Enter ham ishlaydi
  • e.preventDefault() — sahifa qayta yuklanmasin
  • <button type="submit">; JSX da htmlFor, minLength, autoComplete
  • Brauzer validatsiyasi (required, type) onSubmit dan oldin ishlaydi
  • Controlled: bitta state obyekti + name bo'yicha bitta handleChange
  • Uncontrolled: Object.fromEntries(new FormData(e.currentTarget))
  • number input qiymati — string
  • Yuborishda: holat, <fieldset disabled>, role="alert" bilan xato

Keyingi dars

63-dars: React Hook Form — o'rnatish, register, handleSubmit