Mundarija (32)
- Bu darsda
- 1. Nega bu kerak?
- 2. Matn maydoni: value + onChange
- 2.1 Birinchi controlled input
- 2.2 onChange siz value — qotib qolgan maydon
- 2.3 Qiymatni o'zgartirib saqlash
- 2.4 Jonli tekshiruv
- 3. Har bir input turi
- 3.1 textarea
- 3.2 select
- 3.3 Bir nechta tanlov: multiple
- 3.4 Checkbox: checked
- 3.5 Radio: bitta qiymat, ko'p tugma
- 4. Number input — baribir satr
- 5. Ko'p maydonli forma: bitta onChange
- 6. Ikki tuzoq: undefined va null
- 6.1 Uncontrolled'dan controlled'ga sakrash
- 6.2 null qiymat
- 7. value yoki defaultValue?
- 8. Vazifalar qadami: controlled tahrir maydoni
- 8.1 Oldin: matn DOM'da
- 8.2 Keyin: matn state'da
- 8.3 Qidiruv va saralash — allaqachon controlled
- 9. Ko'p uchraydigan xatolar
- 10. Mashqlar
- 1-mashq (oson): To'g'ri xususiyat
- 2-mashq (o'rta): Choy buyurtmasi
- 3-mashq (qiyin): Bron formasi TypeScript'da
- 4-mashq: Vazifalar qadami
- 11. Real ishda
- Xulosa
- Manbalar
Formalar I: controlled inputlar — value, onChange va har bir input turi
Qisqacha: Controlled input — qiymati React state'idan keladigan maydon:
value={name}vaonChange={(e) => setName(e.target.value)}. Har harfonChangeni chaqiradi, state yangilanadi, React maydonni yangi qiymat bilan qayta chizadi. Shunda maydondagi matn har doim state'ga teng: uni tekshirish, o'zgartirish (katta harf), boshqa joyda ko'rsatish yoki tashqaridan tozalash oson. Checkbox va radio'davalueemas —checked;<textarea>va<select>da hamvalue.type="number"maydon baribir satr qaytaradi.valuenionChangesiz bersangiz — maydon qotib qoladi.
Bu darsda
- Matn maydonini
value+onChangebilan boshqarasiz. textarea,select(bir va bir nechta tanlov),checkboxvaradioni controlled qilasiz.- Number input nega satr qaytarishini va uni qanday songa aylantirishni bilasiz.
- Bitta
onChangebilan ko'p maydonli formani boshqarasiz. - React'ning to'rtta forma ogohlantirishini o'qib, tuzatasiz.
vazifalardagi tahrir maydonini controlled qilasiz.
Oldin bilishingiz kerak: State'ni ko'tarish, Hodisalarni boshqarish, Forma qiymatlarini o'qish va submit.
1. Nega bu kerak?
State'ni ko'tarish darsida "controlled komponent" ni ko'rdik: qiymat props'dan keladi, o'zgarish callback bilan so'raladi. Endi xuddi shu g'oya brauzerning eng oddiy elementiga — <input> ga qo'llanadi.
Vanilla JavaScript'da forma qiymatini qanday olardik? Forma qiymatlarini o'qish darsidagidek: yuborilganda input.value ni o'qiymiz. Bu yerda haqiqat manbai — DOM: maydondagi matnni faqat brauzer biladi. Kod uni so'raganda oladi.
Bu ba'zan yetarli. Lekin «Bahor» buyurtma formasida Jasur aka ko'proq narsa so'radi:
- telefon maydoni yozilayotganda "9 ta raqam kerak" deb darhol ogohlantirsin;
- promokod har doim katta harf bilan ko'rinsin;
- "Mehmonlar soni" ga qarab narx darhol hisoblansin;
- buyurtma yuborilgach, forma tozalansin.
Bularning hammasi "maydondagi qiymatni har lahzada bilish va o'zgartira olish" ni talab qiladi. Vanilla'da buning uchun input hodisasini tinglash, qiymatni o'qish, tekshirish va DOM'ga qaytarib yozish kerak. Ikki joyda haqiqat: o'zgaruvchida va maydonda. React'da maydon qiymatini state'ga beramiz — haqiqat bitta bo'ladi.
Hayotiy o'xshatish: oshxonadagi buyurtma taxtasi. Ofitsiant mehmon aytganini (hodisa) bosh oshpazga aytadi (setter). Oshpaz taxtaga yozadi (state). Zaldagi ekran esa doim taxtadagini ko'rsatadi (value). Ekranga hech kim to'g'ridan-to'g'ri yozmaydi.
2. Matn maydoni: value + onChange
2.1 Birinchi controlled input
import { useState } from "react";
function App() {
const [name, setName] = useState("");
return (
<form>
<label>
Ismingiz{" "}
<input
value={name}
onChange={(e) => setName(e.target.value)}
/>
</label>
<p>Salom, {name || "mehmon"}!</p>
<p>Belgilar: {name.length}</p>
</form>
);
}Ekranda:
Ismingiz
Salom, Malika!
Belgilar: 6(Maydon ichidagi matn ekran natijasiga kirmaydi — u <p> lar orqali ko'rinadi.) Har harf uchun aylanish shunday:
sequenceDiagram
participant U as Foydalanuvchi
participant I as input
participant R as React
U->>I: "M" bosdi
I->>R: onChange (e.target.value = "M")
R->>R: setName("M") — yangi render
R->>I: value = "M"| Qadam | name |
Maydonda | <p> da |
|---|---|---|---|
| boshida | "" |
bo'sh | Salom, mehmon! |
| "M" | "M" |
M | Salom, M! |
| … "Malika" | "Malika" |
Malika | Salom, Malika! |
Ikki narsa birga ishlaydi: value={name} — "maydonda state'dagi qiymat tursin", onChange — "foydalanuvchi o'zgartirmoqchi bo'lsa, state'ni yangila". Ikkalasi bo'lmasa, controlled input ishlamaydi.
React'da onChange — har harfda ishlaydi, brauzerning input hodisasiga o'xshab. Vanilla'dagi change hodisasi esa maydondan chiqqandagina keladi. React ataylab shunday nomlagan — boshida chalg'itadi, keyin o'rganib qolasiz.
2.2 onChange siz value — qotib qolgan maydon
onChange ni unutsak:
function App() {
return <input value="Osh" />;
}Konsolda:
You provided a `value` prop to a form field without an `onChange` handler. This will render a read-only field. If the field should be mutable use `defaultValue`. Otherwise, set either `onChange` or `readOnly`."Siz maydonga value berdingiz, lekin onChange ishlovchisini bermadingiz. Maydon faqat o'qish uchun bo'ladi. O'zgaradigan bo'lishi kerak bo'lsa — defaultValue ishlating. Aks holda onChange yoki readOnly qo'ying." Maydonga harf yozib ko'rsangiz — hech narsa o'zgarmaydi. React har bosishda maydonni yana "Osh" ga qaytaradi, chunki state o'zgarmadi.
Ogohlantirish uch yo'lni ko'rsatadi: maydon o'zgarishi kerak bo'lsa — onChange (controlled) yoki defaultValue (uncontrolled, keyingi darsda); faqat ko'rsatish uchun bo'lsa — readOnly.
2.3 Qiymatni o'zgartirib saqlash
Controlled input'ning kuchi — siz onChange da kelgan qiymatni o'zgartirib saqlay olasiz. Promokod har doim katta harf bilan:
import { useState } from "react";
function App() {
const [code, setCode] = useState("");
return (
<>
<label>
Promokod{" "}
<input
value={code}
onChange={(e) => setCode(e.target.value.toUpperCase())}
maxLength={10}
/>
</label>
<p>Kod: {code}</p>
</>
);
}Ekranda:
Promokod
Kod: BAHOR10Foydalanuvchi kichik harf yozdi, maydonda esa katta harf turibdi. Telefon raqamidan faqat raqamlarni qoldirish ham shunday: e.target.value.replace(/\D/g, "") (RegExp asoslari darsidagi \D — "raqam bo'lmagan belgi").
2.4 Jonli tekshiruv
Qiymat state'da bo'lgani uchun xato xabari — hosilaviy qiymat:
import { useState } from "react";
function App() {
const [phone, setPhone] = useState("");
const digits = phone.replace(/\D/g, "");
const error =
digits.length > 0 && digits.length !== 9
? `9 ta raqam kerak, hozir ${digits.length} ta`
: null;
return (
<>
<label>
Telefon{" "}
<input
value={phone}
onChange={(e) => setPhone(e.target.value)}
aria-invalid={error !== null}
aria-describedby="phone-error"
/>
</label>
<p id="phone-error">{error}</p>
</>
);
}Ekranda:
Telefon
9 ta raqam kerak, hozir 5 taerror alohida state emas — har renderda phone dan hisoblanadi. aria-invalid va aria-describedby — Qulay va accessible forma darsidagi juftlik: Malikaning ekran o'quvchisi maydonga kelganda xato matnini ham o'qiydi.
Diqqat: Har harfda xato chiqarish ba'zan bezovta qiladi: foydalanuvchi hali yozib bo'lmagan. Ko'p formalarda xato maydondan chiqqanda (
onBlur) yoki yuborishda ko'rsatiladi. Bu UX tanlovi — controlled input ikkalasiga ham imkon beradi.
Tekshirib ko'ring:
onChange={(e) => setName(e.target.value.trim())}yozilsa, foydalanuvchi "Ali Valiyev" ni yoza oladimi?
Javob
Yo'q. "Ali" dan keyin bo'sh joy bosilganda "Ali " keladi, trim() uni "Ali" ga qaytaradi va maydonda bo'sh joy hech qachon paydo bo'lmaydi — "AliValiyev" bo'lib yoziladi. trim() ni yuborishda qiling, onChange da emas. Qoida: onChange dagi o'zgartirish yozishga xalaqit bermasin.
3. Har bir input turi
3.1 textarea
HTML'da <textarea> matni teglar orasida yoziladi. React'da — value bilan, xuddi <input> kabi:
import { useState } from "react";
function App() {
const [note, setNote] = useState("");
return (
<>
<label>
Izoh{" "}
<textarea
value={note}
onChange={(e) => setNote(e.target.value)}
rows={3}
/>
</label>
<p>Qoldi: {200 - note.length} belgi</p>
</>
);
}Ekranda:
Izoh Piyozsiz bo'lsin
Qoldi: 184 belgitextarea dagi matn ekran natijasiga kiradi — u element ichidagi matn tuguni sifatida ham ko'rinadi (input qiymati esa kirmaydi). Eski HTML odatidagidek matnni ichiga yozsangiz — <textarea>salom</textarea> — React ogohlantiradi: Use the `defaultValue` or `value` props instead of setting children on <textarea>. ("Ichiga bola yozish o'rniga defaultValue yoki value ishlating").
3.2 select
HTML'da tanlangan variant <option selected> bilan belgilanadi. React'da — <select> ning o'zida value:
import { useState } from "react";
function App() {
const [dish, setDish] = useState("osh");
return (
<>
<label>
Taom{" "}
<select
value={dish}
onChange={(e) => setDish(e.target.value)}
>
<option value="osh">Osh</option>
<option value="lagmon">Lag'mon</option>
<option value="manti">Manti</option>
</select>
</label>
<p>Tanlandi: {dish}</p>
</>
);
}Ekranda:
Taom OshLag'monManti
Tanlandi: manti(<option> matnlari ham ekran natijasiga kiradi — ular <select> ichidagi matn.) <option selected> yozsangiz, React aytadi: Use the `defaultValue` or `value` props on <select> instead of setting `selected` on <option>. Sabab bitta: tanlov — select ning qiymati, uni bitta joyda saqlash oson.
3.3 Bir nechta tanlov: multiple
multiple li select ning qiymati — massiv:
import { useState } from "react";
function App() {
const [extras, setExtras] = useState(["non", "choy"]);
function handleChange(e) {
// selectedOptions — tanlangan <option> lar ro'yxati
setExtras(Array.from(e.target.selectedOptions, (o) => o.value));
}
return (
<>
<select multiple value={extras} onChange={handleChange}>
<option value="non">Non</option>
<option value="choy">Ko'k choy</option>
<option value="salat">Salat</option>
</select>
<p>Qo'shimcha: {extras.join(", ")}</p>
</>
);
}Ekranda:
NonKo'k choySalat
Qo'shimcha: non, choye.target.value bu yerda faqat birinchi tanlanganini beradi — shuning uchun selectedOptions dan massiv yasaymiz (Array.from ning ikkinchi argumenti — har elementni o'zgartiruvchi funksiya, Array.from darsida). Kompyuterda bir nechtasini tanlash — Ctrl (macOS'da Cmd) bilan bosish. Telefonda esa bunday ro'yxat noqulay — ko'pincha checkbox'lar guruhi afzal.
3.4 Checkbox: checked
Checkbox'ning "qiymati" — belgilangan yoki yo'q. Shuning uchun value emas, checked, va e.target.value emas, e.target.checked:
import { useState } from "react";
function App() {
const [noOnion, setNoOnion] = useState(false);
return (
<>
<label>
<input
type="checkbox"
checked={noOnion}
onChange={(e) => setNoOnion(e.target.checked)}
/>
Piyozsiz
</label>
<p>{noOnion ? "Oshpazga: piyozsiz!" : "Odatdagidek"}</p>
</>
);
}Ekranda:
Piyozsiz
Oshpazga: piyozsiz!Ko'p uchraydigan xato — e.target.value ni o'qish. Checkbox'ning value si — HTML atributi (sukut bo'yicha "on"), u belgilanganda ham, belgilanmaganda ham bir xil. onChange siz checked bersangiz — value dagidek ogohlantirish, faqat defaultChecked ni taklif qiladi.
3.5 Radio: bitta qiymat, ko'p tugma
Radio tugmalar guruhi — bitta state. Har tugma "men tanlanganmanmi?" ni state bilan solishtiradi:
import { useState } from "react";
const SIZES = [
{ value: "kichik", label: "Kichik", price: 25000 },
{ value: "orta", label: "O'rta", price: 35000 },
{ value: "katta", label: "Katta", price: 45000 },
];
function App() {
const [size, setSize] = useState("orta");
const price = SIZES.find((s) => s.value === size).price;
return (
<fieldset>
<legend>Osh porsiyasi</legend>
{SIZES.map((s) => (
<label key={s.value}>
<input
type="radio"
name="size"
value={s.value}
checked={size === s.value}
onChange={(e) => setSize(e.target.value)}
/>
{s.label}
</label>
))}
<p>Narx: {price} so'm</p>
</fieldset>
);
}Ekranda:
Osh porsiyasi
KichikO'rtaKatta
Narx: 45000 so'mchecked={size === s.value} — tanlov hosilaviy: uchta boolean emas, bitta size (State strukturasi dagi status qoidasi). name — brauzer uchun guruh nomi (klaviatura bilan strelkalar orasida yurish uchun ham muhim — Bobur shunday tanlaydi). Radio'da onChange faqat tanlangan tugmada keladi — tanlovi bekor bo'lgan tugmada hodisa bo'lmaydi.
4. Number input — baribir satr
«Bahor» bron formasida mehmonlar soni. Sardor bir kishi qo'shib, stol hajmini hisoblamoqchi edi:
import { useState } from "react";
function App() {
const [guests, setGuests] = useState("");
return (
<>
<label>
Mehmonlar{" "}
<input
type="number"
min={1}
value={guests}
onChange={(e) => setGuests(e.target.value)}
/>
</label>
<p>Siz bilan birga: {guests + 1} kishi</p>
</>
);
}Ekranda:
Mehmonlar
Siz bilan birga: 31 kishi3 + 1 = 31! type="number" faqat klaviatura va tekshiruvni o'zgartiradi (telefonda raqamli klaviatura, strelkalar). e.target.value esa har doim satr — "3", va "3" + 1 — satrlarni ulash (Turlarni aniq o'zgartirish darsidagi + tuzog'i).
Tuzatish — state'da satrni saqlab, ishlatishda songa aylantirish:
import { useState } from "react";
function App() {
const [guests, setGuests] = useState("");
const count = Number(guests); // "" → 0, "3" → 3
return (
<>
<label>
Mehmonlar{" "}
<input
type="number"
min={1}
value={guests}
onChange={(e) => setGuests(e.target.value)}
/>
</label>
<p>
{guests === ""
? "Sonni kiriting"
: `Jami: ${count + 1} kishi`}
</p>
</>
);
}Ekranda:
Mehmonlar
Jami: 4 kishiNega state'ni darhol songa aylantirmaymiz (setGuests(Number(e.target.value)))? Foydalanuvchi maydonni o'chirsa, Number("") — 0, va maydonda o'chirilgan joyda birdan 0 paydo bo'ladi. Yozishga xalaqit beradi. Satr — "foydalanuvchi nima yozgan bo'lsa, o'sha", son esa hisoblash uchun hosilaviy. Alternativa — e.target.valueAsNumber (bo'sh maydonda NaN).
Tekshirib ko'ring: Mehmonlar maydoniga
2.5yozildi.Number(guests)nima qaytaradi va bu yerda nima qilish kerak?
Javob
2.5 — son, xato emas. Lekin yarim mehmon bo'lmaydi: Number.isInteger(count) bilan tekshirib, xato xabarini ko'rsating. Brauzerga ham ayting: step={1} — u holda brauzer tekshiruvi (:invalid) ham kasrni rad etadi (Brauzer validatsiyasi).
5. Ko'p maydonli forma: bitta onChange
Har maydonga alohida useState va alohida funksiya — beshta maydonda o'nta nom. Bog'liq qiymatlar bitta obyektda (State strukturasi dagi "guruhlash" qoidasi), ishlovchi esa bitta — name atributi bo'yicha:
import { useState } from "react";
function App() {
const [form, setForm] = useState({
name: "",
table: "",
childSeat: false,
});
function handleChange(e) {
const { name, type, value, checked } = e.target;
const next = type === "checkbox" ? checked : value;
setForm({ ...form, [name]: next });
}
return (
<form>
<label>
Ism{" "}
<input
name="name"
value={form.name}
onChange={handleChange}
/>
</label>
<label>
Stol{" "}
<input
name="table"
value={form.table}
onChange={handleChange}
/>
</label>
<label>
<input
type="checkbox"
name="childSeat"
checked={form.childSeat}
onChange={handleChange}
/>
Bolalar stuli
</label>
<p>{JSON.stringify(form)}</p>
</form>
);
}Ekranda:
Ism Stol Bolalar stuli
{"name":"Bobur","table":"7","childSeat":true}[name]: … — hisoblanadigan kalit (computed kalitlar): name o'zgaruvchisidagi satr kalit bo'ladi. ...form — boshqa maydonlar saqlanadi (immutable yangilash). Maydonning name atributi state obyektidagi kalit bilan aynan bir xil bo'lishi shart — bitta harf farqi va yangi kalit paydo bo'ladi.
Katta formalarda (o'nlab maydon, murakkab tekshiruv) qo'lda yozish og'irlashadi. Buning uchun kutubxonalar bor — React Hook Form, 19-qismda. Ular ichida aynan shu darsdagi va keyingi darsdagi g'oyalar.
6. Ikki tuzoq: undefined va null
6.1 Uncontrolled'dan controlled'ga sakrash
useState() boshlang'ich qiymatsiz — undefined:
import { useState } from "react";
function App() {
const [name, setName] = useState(); // ❌ undefined
return (
<label>
Ism{" "}
<input value={name} onChange={(e) => setName(e.target.value)} />
</label>
);
}Konsolda:
A component is changing an uncontrolled input to be controlled. This is likely caused by the value changing from undefined to a defined value, which should not happen. Decide between using a controlled or uncontrolled input element for the lifetime of the component. More info: https://react.dev/link/controlled-components"Komponent uncontrolled input'ni controlled'ga aylantiryapti. Ehtimol qiymat undefined dan aniq qiymatga o'zgargani sabab — bunday bo'lmasligi kerak. Input butun umri davomida controlled yoki uncontrolled bo'lishini hal qiling." React uchun value={undefined} — "value berilmagan", ya'ni uncontrolled. Birinchi harfdan keyin value="A" — controlled. Tuzatish: useState("").
Xuddi shu xato ma'lumot serverdan kelganda ham chiqadi: value={user.phone} va phone hali yo'q (undefined). Davosi — zaxira: value={user.phone ?? ""}.
6.2 null qiymat
function App() {
return <input value={null} onChange={() => {}} />;
}Konsolda:
`value` prop on `input` should not be null. Consider using an empty string to clear the component or `undefined` for uncontrolled components."input dagi value null bo'lmasligi kerak. Maydonni tozalash uchun bo'sh satr, uncontrolled uchun undefined ishlating." Ma'lumotlar bazasidan bo'sh maydon ko'pincha null bo'lib keladi — yana ?? "".
7. value yoki defaultValue?
value (controlled) |
defaultValue (uncontrolled) |
|
|---|---|---|
| Haqiqat manbai | React state | DOM (brauzer) |
| Har harfda render | ha | yo'q |
| Tashqaridan tozalash/o'zgartirish | setX("") |
qiyin (ref yoki key) |
| Jonli tekshiruv, formatlash | oson | qiyin |
| Kod hajmi | ko'proq | kam |
| Checkbox/radio | checked |
defaultChecked |
Qachon controlled tanlanadi: qiymat yozilayotganda kerak bo'lsa — jonli tekshiruv, formatlash, boshqa maydonga ta'siri, tashqaridan tozalash. Qiymat faqat yuborilganda kerak bo'lsa, uncontrolled yetadi va soddaroq — keyingi darsda.
"Har harfda render — sekin emasmi?" Oddiy formada — yo'q: bir nechta element qayta chiziladi, bu mikrosoniyalar. Muammo faqat maydon juda katta komponentning state'iga bog'langanda chiqadi. Masalan, App dagi state'ga har harfda 1 000 qatorli ro'yxat qayta chizilsa. vazifalar da qidiruv aynan shunday — 1 000 vazifada o'lchab ko'rganmiz (mini-ilova darsi).
8. Vazifalar qadami: controlled tahrir maydoni
8.1 Oldin: matn DOM'da
Hozir (refactor/app-ildizi birlashtirilgan holat) tahrir maydoni — uncontrolled:
{/* defaultValue — boshlang'ich qiymat, keyin maydon o'ziniki
(uncontrolled). Fon yangilanganda React shu <input> ni
QAYTA YARATMAYDI — yozilayotgan matn joyida qoladi */}
<input
id={TAHRIR_MAYDONI_ID}
defaultValue={vazifa.matn}"Saqlash" bosilganda asosiy.ts matnni DOM'dan qidiradi:
function tahrirniSaqla(): void {
const id = holat.tahrirId;
const kiritma = tahrirMaydoni();
if (id === null || kiritma === null) {
return; // tahrir yopilgan — saqlanadigan narsa yo'q
}
const matn = kiritma.value.trim();tahrirMaydoni() — document.getElementById("tahrir-maydon"). React chizgan elementni vanilla kod id bo'yicha qidiradi — ikki dunyo o'rtasidagi "yashirin ip". Id o'zgarsa yoki ikkita tahrir maydoni paydo bo'lsa, u jim buziladi.
8.2 Keyin: matn state'da
Yangi branch: refactor/formalar (commit — keyingi darsda, formalar bilan birga). TahrirQatori.tsx diff'i (kanondan):
export function TahrirQatori({ vazifa, onSaqla, onBekor }: Props) {
+ // Controlled (17/#18): maydondagi matn — state, maydon uni ko'rsatadi.
+ // Fon yangilanganda (server, boshqa tab) qator key bilan saqlanadi —
+ // yozilayotgan matn ham shu state'da qoladi. v6 da qator qayta
+ // yasalardi va matnni qo'lda tiklardik (fondaChiz)
+ const [matn, setMatn] = useState(vazifa.matn);
+
…
if (event.key === "Enter") {
event.preventDefault();
- onSaqla();
+ onSaqla(matn);
…
<input
id={TAHRIR_MAYDONI_ID}
- defaultValue={vazifa.matn}
+ value={matn}
+ onChange={(event) => setMatn(event.target.value)}
maxLength={Vazifa.MAKS_UZUNLIK}
aria-label="Vazifa matni"
onKeyDown={tugmaBosildi}
…
- onClick={onSaqla}
+ onClick={() => onSaqla(matn)}Uch narsa o'zgardi:
useState(vazifa.matn)— State strukturasi dagi "ataylab nusxa": tahrir boshlanganda vazifa matni olinadi, keyin foydalanuvchi o'zi yozadi. Server vazifani boshqa matnga o'zgartirsa ham, yozilayotgan matn bosib ketilmaydi.onSaqla(matn)— matn callback argumenti bo'lib otaga ketadi (callback props).turlar.tsda tur:readonly onSaqla: (matn: string) => void;.asosiy.tsendi DOM'ga qaramaydi:
// Matn — TahrirQatori state'idan (17/#18), DOM'dan emas
function tahrirniSaqla(yangiMatn: string): void {
const id = holat.tahrirId;
if (id === null) {
return; // tahrir yopilgan — saqlanadigan narsa yo'q
}
const matn = yangiMatn.trim();trim() — saqlashda, onChange da emas («Jonli tekshiruv» bo'limidagi savolni eslang). isComposing tekshiruvi (xitoy, yapon klaviaturasidagi tanlov oynasi) o'zgarmadi: Enter bosilganda onSaqla(matn) faqat yozish tugagan bo'lsa chaqiriladi.
8.3 Qidiruv va saralash — allaqachon controlled
State'ni ko'tarish darsida yozilgan QidiruvMaydoni endi tushunarli:
{/* value — holatdan (controlled, #18 da batafsil): vazifa
qo'shilganda yoki import'da holat qidiruvni tozalasa, maydon
ham bo'shaydi. type="search": Esc va × ham — onChange keladi */}
<input
type="search"
id="qidiruv"
maxLength={100}
autoComplete="off"
value={qidiruv}
onChange={(event) => onQidir(event.target.value)}
/>Bu yerda state App da emas — vanilla do'konda, lekin qoida o'sha: value + onChange. v6 da qidiruvniYoz() har chizishda if (maydon.value !== holat.qidiruv) maydon.value = holat.qidiruv qilardi — qo'lda sinxronlash. Controlled maydon buni o'zi qiladi.
Yangi vazifa formasi esa uncontrolled qoladi — ataylab. Nega — keyingi darsda.
9. Ko'p uchraydigan xatolar
| Belgi / xabar | Sabab | Davosi |
|---|---|---|
maydonga yozib bo'lmaydi; without an onChange handler |
value bor, onChange yo'q |
onChange qo'shing yoki defaultValue/readOnly |
changing an uncontrolled input to be controlled |
useState() yoki value={undefined} |
useState(""), ?? "" |
should not be null |
value={null} |
?? "" |
checkbox doim "on" |
e.target.value o'qilgan |
e.target.checked |
3 + 1 = 31 |
number input satr qaytaradi | Number(x) yoki valueAsNumber |
| bo'sh joy yozib bo'lmaydi | onChange da trim() |
yuborishda trim() |
selected / textarea bolasi ogohlantirishi |
HTML odati | select va textarea da value |
10. Mashqlar
Mashqlar kurs/mashqlar/17/18-controlled-inputlar/ da.
1-mashq (oson): To'g'ri xususiyat
Bo'sh joylarni to'ldiring:
- Checkbox holatini o'qish:
e.target. <select>da tanlangan variantni belgilash uchun prop:type="number"maydondae.target.valuening turi:- Bo'sh controlled matn maydoni uchun
useStateboshlang'ich qiymati:
Yechim
checked — checkbox'ning belgilangani; value — select ning o'zida (<option selected> emas); string — number input ham satr qaytaradi; "" — undefined emas, aks holda "uncontrolled'dan controlled'ga" ogohlantirishi.
2-mashq (o'rta): Choy buyurtmasi
Forma: choy turi (select: ko'k choy 5 000, qora choy 6 000), choynaklar soni (type="number", boshlang'ich "1"), "Limon qo'shilsin" checkbox (+2 000 bitta choynakka). Pastda — "Jami: N so'm" (hosilaviy). Soni bo'sh bo'lsa — "Sonni kiriting". Hammasi controlled bo'lsin.
Yechim
import { useState } from "react";
const PRICES = { kok: 5000, qora: 6000 };
function App() {
const [tea, setTea] = useState("kok");
const [count, setCount] = useState("1");
const [lemon, setLemon] = useState(false);
const n = Number(count);
const total = n * (PRICES[tea] + (lemon ? 2000 : 0));
return (
<form>
<label>
Choy{" "}
<select value={tea} onChange={(e) => setTea(e.target.value)}>
<option value="kok">Ko'k choy</option>
<option value="qora">Qora choy</option>
</select>
</label>
<label>
Choynak{" "}
<input
type="number"
min={1}
value={count}
onChange={(e) => setCount(e.target.value)}
/>
</label>
<label>
<input
type="checkbox"
checked={lemon}
onChange={(e) => setLemon(e.target.checked)}
/>
Limon
</label>
<p>{count === "" ? "Sonni kiriting" : `Jami: ${total} so'm`}</p>
</form>
);
}Ekranda:
Choy Ko'k choyQora choyChoynak Limon
Jami: 16000 so'm2 × (6 000 + 2 000) = 16 000. Jami — hosilaviy: uchta state'dan hisoblanadi. yoz("Choynak", "2") maydonni tozalab "2" yozadi.
3-mashq (qiyin): Bron formasi TypeScript'da
TypeScript'da bitta state obyektli forma: name (matn), guests (number input, satr), time (radio: "12:00", "18:00", "20:00"), smoking (checkbox: "Chekish zonasi"). Bitta handleChange — ChangeEvent<HTMLInputElement> turi bilan. Pastda xulosa: "Bobur, 4 kishi, 18:00" (chekish zonasi tanlansa — oxiriga ", chekish zonasi"). Ism bo'sh yoki mehmonlar 1–12 oralig'ida bo'lmasa — "Formani to'ldiring". Ishora: ChangeEvent — react dan tur importi (React + TS III da batafsil, hozir import type { ChangeEvent } from "react"; yetadi).
Yechim
import { useState } from "react";
import type { ChangeEvent } from "react";
type Booking = {
name: string;
guests: string;
time: string;
smoking: boolean;
};
const TIMES = ["12:00", "18:00", "20:00"];
export default function App() {
const [form, setForm] = useState<Booking>({
name: "",
guests: "",
time: "12:00",
smoking: false,
});
function handleChange(e: ChangeEvent<HTMLInputElement>) {
const { name, type, value, checked } = e.target;
const next = type === "checkbox" ? checked : value;
setForm({ ...form, [name]: next });
}
const n = Number(form.guests);
const valid =
form.name.trim() !== "" &&
Number.isInteger(n) &&
n >= 1 &&
n <= 12;
return (
<form>
<label>
Ism{" "}
<input
name="name"
value={form.name}
onChange={handleChange}
/>
</label>
<label>
Mehmonlar{" "}
<input
type="number"
name="guests"
value={form.guests}
onChange={handleChange}
/>
</label>
{TIMES.map((t) => (
<label key={t}>
<input
type="radio"
name="time"
value={t}
checked={form.time === t}
onChange={handleChange}
/>
{t}
</label>
))}
<label>
<input
type="checkbox"
name="smoking"
checked={form.smoking}
onChange={handleChange}
/>
Chekish zonasi
</label>
<p>
{valid
? `${form.name.trim()}, ${n} kishi, ${form.time}` +
(form.smoking ? ", chekish zonasi" : "")
: "Formani to'ldiring"}
</p>
</form>
);
}Ekranda:
Ism Mehmonlar 12:0018:0020:00Chekish zonasi
Bobur, 4 kishi, 18:00Radio guruhida ham name="time" — u bir vaqtda brauzer guruhi va state kaliti. valid — hosilaviy. [name] kaliti string bo'lgani uchun TypeScript Booking dagi aniq kalitni tekshira olmaydi — bu usulning narxi; maydon nomlarini xatosiz yozing.
4-mashq: Vazifalar qadami
refactor/formalar branch'ini oching va «Vazifalar qadami» dagi o'zgarishlarni kiriting: TahrirQatori.tsx (useState, value/onChange, onSaqla(matn)), turlar.ts (onSaqla: (matn: string) => void), asosiy.ts (tahrirniSaqla(yangiMatn)). npm run tip va npm test toza bo'lsin. Commit hozircha qilinmaydi.
Yechim
npm run tip—TS2554: Expected 1 arguments, but got 0.chiqsa, biror joyda halionSaqla()argumentsiz chaqirilgan (Enteryoki tugma).- Brauzerda: vazifani tahrirlang, harf qo'shing, ikkinchi tabda boshqa vazifani o'zgartiring — yozilayotgan matn joyida. «Bekor qilish» va qayta «Tahrirlash» — matn vazifaning asl matniga qaytadi (
TahrirQatoriyangidan yaratiladi, State'ning saqlanishi). - Vitest'dagi tahrir testlari o'tadi: ular foydalanuvchi kabi yozadi va «Saqlash» ni bosadi — maydonning ichki tuzilishiga qaramaydi.
11. Real ishda
- Controlled — React'dagi standart yo'l. Qidiruv maydonlari, filtrlar, sozlamalar sahifalari, chat yozish maydoni — deyarli hammasi controlled. UI kutubxonalardagi
value/onChange(Select, DatePicker, Slider) ham shu shartnoma. - Formatlash (telefon
+998 90 …, karta raqami8600 …) — controlled input bilan yoziladi yoki tayyor kutubxona bilan. - Formalar kutubxonalari — React Hook Form, TanStack Form — 19-qismda. Ular ko'pincha uncontrolled yo'lni ishlatadi (keyingi dars) va controlled'ni faqat kerakli maydonlarga qoldiradi.
- Intervyu savollari: "Controlled va uncontrolled input farqi?", "Nega
valuenionChangesiz berish ogohlantirish beradi?", "Checkbox'ni qanday controlled qilasiz?", "A component is changing an uncontrolled input to be controlledxatosi nimadan?".
Xulosa
- Controlled input:
value={state}+onChange={(e) => setState(e.target.value)}— haqiqat React state'ida. textareavaselectda hamvalue;multiple— massiv (selectedOptions); checkbox va radio'dachecked.- Number input satr qaytaradi: state — satr, hisob —
Number(). - Ko'p maydon — bitta obyekt va
nameatributi bo'yicha bitta ishlovchi. useState(""),?? ""—undefined/nullogohlantirishlariga davo;trim()— yuborishda.vazifalardagi tahrir maydoni controlled: matnTahrirQatoristate'ida, saqlash DOM'ga qaramaydi.
Keyingi dars: Formalar II: uncontrolled inputlar, FormData va form action — qiymat faqat yuborishda kerak bo'lsa state shart emas: defaultValue, FormData, React 19 <form action> va nega vazifalar uni ishlatmaydi.
Manbalar
- React:
<input>— react.dev/reference/react-dom/components/input - React:
<select>,<textarea>— react.dev/reference/react-dom/components/select, …/textarea - React: "Reacting to Input with State" — react.dev/learn/reacting-to-input-with-state
- MDN:
HTMLInputElement.valueAsNumber,HTMLSelectElement.selectedOptions— developer.mozilla.org
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!