Mundarija (28)
- Bu darsda
- 1. Nega bu kerak?
- 2. Props nomlash
- 3. Boolean prop portlashi
- 3.1 Muammo — raqamlarda
- 3.2 Ikki variant yonma-yon
- 3.3 TypeScript qo'riqchisi
- 3.4 Ikkinchi o'q: size
- 4. Native atributlar: o'rgatmang, uzating
- 4.1 ComponentPropsWithoutRef<"button"> va ...rest
- 4.2 className — qo'shiladi
- 4.3 Xavfsiz standart: type="button"
- 4.4 ref — oddiy props
- 5. Konfiguratsiya o'rniga kompozitsiya
- 6. API tekshiruv ro'yxati
- 7. Vazifalar qadami: Tugma (holat 33)
- 7.1 src/ui/Tugma.tsx
- 7.2 To'qqiz joyga
- 7.3 Nega Tugma polymorphic emas?
- 8. Ko'p uchraydigan xatolar
- 9. Mashqlar
- 1-mashq (oson): nomlarni tuzating
- 2-mashq (o'rta): Badge — boolean'lardan variantga
- 3-mashq (qiyin): TextField API'si
- 4-mashq: vazifalar qadami
- 10. Real ishda
- Xulosa
- Manbalar
Komponent API'sini loyihalash: props nomlash, variant va native atributlar
Qisqacha: Yaxshi komponent API'si — kam va aniq props. Ko'rinish bitta
variantbilan ("oddiy" | "asosiy" | "xavfli"), bir-biriga zid bo'la oladigan boolean'lar to'plami (primary,danger,outline) bilan emas. Qolgan hamma narsa — native atributlar:ComponentPropsWithoutRef<"button">va...restorqaliid,aria-*,onClicko'rganishsiz ishlaydi.classNamealmashtirilmaydi, qo'shiladi. Standart qiymat xavfsiz bo'lsin (type="button"). Kontent — props emas,children(kompozitsiya).vazifalarda shu qoidalar bilanTugmayasaymiz va uni 9 joyga qo'yamiz.
Bu darsda
- Props'ni React va DOM odatlariga mos nomlaysiz.
- Boolean prop portlashi nima ekanini va uni
variantunion bilan qanday davolashni ko'rsata olasiz. - Komponentni
ComponentPropsWithoutRef<"button">bilan kengaytirib,...restvaclassNameni to'g'ri uzatasiz. - Xavfsiz standart qiymatlar va "konfiguratsiya o'rniga kompozitsiya" tamoyilini qo'llaysiz.
vazifalargaTugmakomponentini qo'shib, uni ilovadagi tugmalarga joylaysiz.
Oldin bilishingiz kerak: Polymorphic komponentlar va asChild, Headless komponentlar va prop getters, Reducer, Immer va holat mashinasi fikrlashi.
1. Nega bu kerak?
Oldingi darsda useMenyu ning API'sini — getterlarni — loyihaladik. Endi oddiyroq, lekin har kuni ishlatiladigan narsaga qaytamiz: tugma.
vazifalar da hozir to'qqizta <button> bor. Har birida type="button" qo'lda yozilgan, o'chirish dialogidagi tugmada .xavfli klassi, «Qo'shish» tugmasi esa boshqalardan hech farq qilmaydi — dizayner uni "asosiy" qilishni so'radi. Sardorga topshiriq: Tugma komponentini yasash.
Uning birinchi varianti:
<Button primary>Qo'shish</Button>
<Button danger outline small>O'chirish</Button>
<Button primary danger>???</Button>Bir oy o'tib Button da 11 ta props bor edi: primary, secondary, danger, outline, ghost, small, large, loading, icon, iconRight, fullWidth. Uchinchi qatorga qarang: primary danger — yashilmi yoki qizilmi? Kodni ochmasdan hech kim bilmaydi. Kod esa if (primary) … else if (danger) … — tartib tasodifiy.
Komponent API'si — boshqa dasturchilar (va bir oydan keyingi siz) bilan shartnoma. Uni bir marta yozasiz, yuz marta o'qiladi. Yomon shartnomani keyin o'zgartirish qimmat: har o'zgarish uni ishlatgan barcha joylarni buzadi.
Hayotiy o'xshatish: choyxonadagi buyurtma varaqasi. Yaxshi varaqada "choy: ko'k / qora" — bittasini belgilaysiz. Yomon varaqada ikki alohida katak: "ko'k choy " va "qora choy ". Ofitsiant ikkalasini belgilasa, oshpaz nima damlaydi? Varaqaning o'zi xato qilishga imkon beradi.
2. Props nomlash
Nomlar — API'ning eng ko'p o'qiladigan qismi. Qoida bitta: foydalanuvchi allaqachon biladigan nomni ishlating. React dasturchisi DOM va React odatlarini biladi:
| Qoida | ||
|---|---|---|
| Native nom bor bo'lsa — o'sha | disabled, onClick, type |
isDisabled, onPress, kind |
Hodisa — on + nima bo'ldi |
onOpenChange, onSelect |
openHandler, handleSelect |
| Boolean — ijobiy shakl | disabled, open |
notEnabled, hidden={!visible} |
Kontent — children |
<Tugma>Saqlash</Tugma> |
<Tugma label="Saqlash" /> |
| Bir xil ma'no — bir xil nom | hamma joyda variant |
birida variant, birida type, birida kind |
| Qisqartma yo'q | description |
desc, dscr |
Ikkinchi qator #27 dagi uchlik bilan bog'liq: open / defaultOpen / onOpenChange. handle… — ishlovchi funksiyaning ichki nomi (handleClick), props nomi emas. Props — on…, uning qiymati — handle…: onClick={handleClick} (Hodisalarni boshqarish).
Izchillik alohida qoida. Loyihadagi o'nta komponentdan biri ko'rinishni type bilan, boshqasi variant bilan, uchinchisi color bilan bersa, har safar hujjatga qarash kerak. Dizayn tizimi bir lug'at tanlaydi va hamma komponentda shunga amal qiladi.
vazifalar da nomlar o'zbekcha, lekin xuddi shu odatlar bilan: variant, ochiq/boshlangichOchiq/onOchiqOzgardi, onTanla.
3. Boolean prop portlashi
3.1 Muammo — raqamlarda
Har yangi boolean props mumkin bo'lgan holatlarni ikki baravar oshiradi. primary va danger — 4 kombinatsiya; outline qo'shilsa — 8; ghost — 16. Ularning ko'pchiligi ma'nosiz (primary + ghost + danger?), lekin TypeScript ham, kod ham ularni taqiqlamaydi:
- 1 boolean2 ta
- 2 boolean4 ta
- 3 boolean8 ta
- 4 boolean16 ta
- variant (4 qiymat)hammasi ma'noli4 ta
Manba: Hisob: n ta boolean — 2ⁿ kombinatsiya; bitta union props — qiymatlar soni
Grafikdagi oxirgi ustun — bitta variant props'i to'rt qiymat bilan: to'rt holat, hammasi ma'noli, ziddiyat imkonsiz. Bu — holat mashinasi darsidagi "imkonsiz holatlarni imkonsiz qilish" g'oyasi, endi props'da.
3.2 Ikki variant yonma-yon
function BoolButton({ primary, danger, children }) {
// Qaysi biri yutadi? Faqat kod biladi
const color = primary ? "yashil" : danger ? "qizil" : "kulrang";
return <button data-color={color}>{children} ({color})</button>;
}
function VariantButton({ variant = "oddiy", children }) {
return (
<button data-variant={variant}>
{children} ({variant})
</button>
);
}
function App() {
return (
<div>
<p>
<BoolButton primary danger>
O'chirish
</BoolButton>
</p>
<p>
<VariantButton variant="xavfli">O'chirish</VariantButton>
</p>
</div>
);
}Ekranda:
O'chirish (yashil)
O'chirish (xavfli)primary danger — o'chirish tugmasi yashil chiqdi: primary tekshiruvi birinchi turgani uchun. Xato jim, sahifada hech kim payqamaydi — foydalanuvchi esa xavfli amalni xavfsiz deb o'ylaydi. variant bilan bunday xato yozib bo'lmaydi: props bitta, qiymat bitta.
3.3 TypeScript qo'riqchisi
variant ni literal turlar union'i bilan tiplasak, noto'g'ri qiymat kompilyatsiyada ushlanadi:
import type { ComponentPropsWithoutRef } from "react";
type ButtonProps = ComponentPropsWithoutRef<"button"> & {
variant?: "oddiy" | "asosiy" | "xavfli";
};
function Button({ variant = "oddiy", ...rest }: ButtonProps) {
return <button data-variant={variant} {...rest} />;
}
function App() {
return <Button variant="qizil">O'chirish</Button>;
}Xato:
TS2322: Type '"qizil"' is not assignable to type '"asosiy" | "oddiy" | "xavfli" | undefined'.""qizil" turi "asosiy" | "oddiy" | "xavfli" | undefined ga mos emas." Muharrir esa variant=" yozilishi bilan uchta to'g'ri qiymatni taklif qiladi. Nomga ham e'tibor bering: "xavfli", "qizil" emas. Variant — ma'no (bu amal xavfli), rang emas. Ertaga dizayner xavfli tugmalarni to'q sariq qilsa, kod o'zgarmaydi.
3.4 Ikkinchi o'q: size
Ko'rinish bir nechta mustaqil o'qqa bo'linsa, har o'q — alohida union props: variant (ma'no) va size ("kichik" | "orta" | "katta"). Ular bir-biriga zid emas: har qanday variant har qanday size bilan ma'noli. 3 × 3 = 9 kombinatsiya — hammasi to'g'ri.
Ba'zan o'qlar kesishganda maxsus qoida kerak bo'ladi: "kichik xavfli tugmada matn qalin bo'lsin". Bunday qoidalar compound variants deyiladi va ularni qo'lda if bilan yozish tezda chalkashadi. Dizayn tizimi: tokenlar va variantlar darsida buning uchun cva vositasini ko'ramiz.
Tekshirib ko'ring:
loading— boolean. U hamvariantga qo'shilishi kerakmi (variant="yuklanmoqda")?
Javob
Yo'q. loading — ko'rinish turi emas, holat: xavfli tugma ham, asosiy tugma ham yuklanishi mumkin. U variant bilan mustaqil o'q, ya'ni alohida props. Boolean bo'lishi to'g'ri — u boshqa boolean'lar bilan to'qnashmaydi. Qoida: bir-birini istisno qiladigan qiymatlar — bitta union; mustaqil holatlar — alohida props.
4. Native atributlar: o'rgatmang, uzating
4.1 ComponentPropsWithoutRef<"button"> va ...rest
Tugma — <button> ning o'rami. Foydalanuvchi unga id, aria-label, value, form, onFocus, title berishni xohlaydi. Har birini alohida props qilib yozish — cheksiz ish va har safar nimadir esdan chiqadi. Yechim: komponent <button> qabul qiladigan hamma narsani qabul qilsin va o'zi ishlatmaydiganini elementga uzatsin:
type Props = ComponentPropsWithoutRef<"button"> & {
variant?: TugmaVarianti;
};
export function Tugma({ variant = "oddiy", ...qolgan }: Props) {
return <button data-variant={variant} {...qolgan} />;
}ComponentPropsWithoutRef<"button"> — #29 dagi tur: <button> ning hamma atributlari. & bilan o'z props'ingiz qo'shiladi. ...qolgan (rest) — destrukturlashda nomlanmagan hamma narsa. Endi <Tugma aria-label="O'chirish: non olish" onClick={…}> — o'rganish shart emas, native'dagidek ishlaydi. Tugmani ishlatgan har kim allaqachon <button> ni biladi.
4.2 className — qo'shiladi
Komponentning o'z klassi bor (tugma). Foydalanuvchi o'zinikini bersa, ...qolgan oxirida yoyilsa — u komponentnikini o'chirib yuboradi, stil yo'qoladi. Shuning uchun className alohida olinadi va birlashtiriladi: className === undefined ? "tugma" : \tugma ${className}`. Natija: →class="tugma qoshish"`. Bu — Slot dagi birlashtirish qoidasining eng sodda holi.
4.3 Xavfsiz standart: type="button"
HTML'da <button> ning standart turi — submit. Forma ichidagi har qanday tugma bosilsa, forma yuboriladi. Buni o'zingiz ko'ring:
function Tugma({ type = "button", ...rest }) {
return <button type={type} {...rest} />;
}
function App() {
return (
<form
onSubmit={(e) => {
e.preventDefault();
console.log("forma yuborildi!");
}}
>
<input placeholder="Vazifa" />
<button onClick={() => console.log("tozalash")}>
Tozalash
</button>{" "}
<Tugma onClick={() => console.log("tozalash (Tugma)")}>
Tozalash (Tugma)
</Tugma>
</form>
);
}Konsolda:
tozalash
forma yuborildi!
tozalash (Tugma)Oddiy <button> "tozalash" bilan birga formani ham yubordi — yangi vazifa tasodifan qo'shildi. Tugma esa faqat o'z ishini qildi. Standart qiymat — eng ko'p uchraydigan holat uchun xavfsiz bo'lsin. Submit kerak bo'lsa, u aniq yoziladi: <Tugma type="submit">. Xavfli narsa aniq ko'rinsin, xavfsizi jim bo'lsin.
4.4 ref — oddiy props
React 19 da ref funksiya komponentga oddiy props bo'lib keladi (useRef II). Uni <button> ga uzatish kifoya — forwardRef kerak emas. vazifalar dagi AmalTugmasi aynan shu yo'l bilan fokus uchun ref oladi. Agar ref ni ...qolgan ichida qoldirsangiz, u ham uzatiladi. Kanon uni aniq nomlaydi — o'qiganda ko'rinib tursin.
5. Konfiguratsiya o'rniga kompozitsiya
Sardorning 11 props'idan ikkitasi — icon va iconRight. Keyin iconSize, iconColor, iconLabel keldi… Har bir kontent turi uchun yangi props. Compound komponentlar darsidagi Tabs items={…} muammosining aynan o'zi.
Kontent — children:
// ❌ konfiguratsiya: har kontent turi uchun props
<Button
icon="trash"
iconRight={false}
iconSize={16}
label="O'chirish"
/>
// ✅ kompozitsiya: kontentni foydalanuvchi o'zi yig'adi
<Tugma variant="xavfli">
<TrashIcon aria-hidden="true" /> O'chirish
</Tugma>Ikkinchi variantda Tugma ikonka haqida hech narsa bilmaydi. Ikonka chapda yoki o'ngda, kattami yoki kichik, <svg> mi yoki rasm — foydalanuvchining ishi. Komponentning props'lari faqat uning o'z qarorlari uchun qoladi: ko'rinish (variant) va xulq (type). Bu — "composition over configuration" (konfiguratsiya o'rniga kompozitsiya) tamoyili.
Qachon props kerak? Komponent kontentga xulq qo'shishi kerak bo'lganda. loading yaxshi misol: tugma o'zi aria-busy, disabled va aylanuvchi belgi qo'yishi kerak — bu kontent emas, holat.
6. API tekshiruv ro'yxati
Yangi komponentni ulashishdan oldin Jasur aka shu savollarni beradi:
| Savol | Yaxshi javob |
|---|---|
| Props soni? | kam: faqat komponentning o'z qarorlari |
| Zid kombinatsiya bormi? | yo'q: bir-birini istisno qiladiganlar — bitta union |
| Native atribut ishlaydimi? | ha: ComponentPropsWithoutRef + ...rest |
className, ref, style? |
qo'shiladi yoki uzatiladi, yo'qolmaydi |
| Standart qiymatlar? | xavfsiz: type="button", variant="oddiy" |
| Kontent? | children orqali |
| Nomlar? | DOM va loyiha lug'ati bilan izchil |
| Kelajakda o'zgarsa? | yangi props qo'shiladi, eskisi buzilmaydi |
Oxirgi qator — semver (semantik versiyalash). Props'ni olib tashlash yoki ma'nosini o'zgartirish — buzuvchi o'zgarish (major). Kutubxonada bu yangi versiya, ilovada — hamma joyni bir PR'da o'zgartirish. Yangi ixtiyoriy props qo'shish — xavfsiz (minor). Shuning uchun boshida kam props bilan boshlang: qo'shish oson, olib tashlash qimmat.
7. Vazifalar qadami: Tugma (holat 33)
Yangi branch: refactor/tugma-tokenlar. Holat 33 uch darsni qamraydi: Tugma (shu dars), xususiyat papkasi (#32) va dizayn tokenlari (#33). Commit — #33 da.
7.1 src/ui/Tugma.tsx
// Tugma.tsx — ilovaning tugmasi (18/#31: komponent API'si).
// Qoidalar: (1) kam va aniq props — ko'rinish bitta "variant"
// bilan, "asosiymi", "xavflimi" kabi boolean'lar to'plami emas
// (ikkalasi true bo'lsa-chi?); (2) qolgan hamma narsa — oddiy
// <button> atributlari (ComponentPropsWithoutRef<"button">,
// ...qolgan): id, aria-*, value, onClick — o'rganish shart emas,
// native'dagidek; (3) xavfsiz standart: type="button" (formada
// tasodifan submit bo'lmasin — submit kerak bo'lsa, aniq
// yoziladi); (4) className qo'shiladi, almashtirmaydi; ref — prop
// (React 19). Ko'rinish — CSS'da data-variant bo'yicha
// (tokenlar, #33)
import type { ComponentPropsWithoutRef, Ref } from "react";
type TugmaVarianti = "oddiy" | "asosiy" | "xavfli";
type Props = ComponentPropsWithoutRef<"button"> & {
variant?: TugmaVarianti;
ref?: Ref<HTMLButtonElement> | undefined;
};
export function Tugma({
variant = "oddiy",
type = "button",
className,
ref,
...qolgan
}: Props) {
return (
<button
ref={ref}
type={type}
className={
className === undefined ? "tugma" : `tugma ${className}`
}
data-variant={variant === "oddiy" ? undefined : variant}
{...qolgan}
/>
);
}Fayl boshidagi izoh — shu darsning qisqa xulosasi: to'rt qoida. Izoh telefonga sig'ishi uchun qayta bo'lindi, kod — aynan kanon. Kodning o'zida uchta detal:
data-variant, klass emas..tugma[data-variant="xavfli"]— atribut bitta qiymatga ega bo'la oladi, ikkita variant bir vaqtda bo'lishi imkonsiz. Klasslar bilan (tugma xavfli asosiy) yana boolean portlashi qaytardi. Radix ham holatni shunday beradi:data-state="open"."oddiy"uchun atribut yo'q.undefined— React atributni umuman yozmaydi. Oddiy tugma —.tugmaning o'zi, DOM toza.ref?: Ref<…> | undefined—exactOptionalPropertyTypesuchun (#27 da ko'rgan sabab):AmalTugmasiref'ni o'z props'idan uzatadi, uundefinedbo'lishi mumkin.
CSS'da .xavfli klassi o'rniga:
/* 18/#31: Tugma variantlari (data-variant) */
.tugma[data-variant="xavfli"] {
border-color: var(--rang-xato);
color: var(--rang-xato);
}
.tugma[data-variant="asosiy"] {
border-color: var(--rang-asosiy);
background: var(--rang-asosiy);
color: var(--rang-asosiy-ustida);
}Ranglar allaqachon CSS o'zgaruvchilari — 17-qismdagi tema (qorong'i rejim). #33 da qolgan qiymatlar ham tokenlarga aylanadi.
7.2 To'qqiz joyga
Tugma oddiy <button> larning o'rnini egalladi. Uch xil holat bor. Oddiy almashtirish (Aloqa.tsx):
- <button
- type="button"
+ <Tugma
id="qayta-tugma"
hidden={tarmoq !== "xato"}
onClick={onQaytaUrin}
>
Qayta urinish
- </button>
+ </Tugma>type="button" qatori o'chdi — endi standart. id, hidden, onClick — native, ...qolgan orqali o'tadi. Asosiy variant (YangiVazifaForma.tsx, «Qo'shish»):
- <button type="submit" id="qoshish-tugma">
+ <Tugma type="submit" id="qoshish-tugma" variant="asosiy">
{pending ? "Qo'shilmoqda…" : "Qo'shish"}
- </button>
+ </Tugma>Bu formaning haqiqiy submit tugmasi, shuning uchun type="submit" aniq yozilgan. Uchinchi holat — o'chirish dialogi (OchirishDialog.tsx):
- <button value="bekor">Bekor qilish</button>
- <button value="ochir" className="xavfli">
+ {/* type="submit": method="dialog" formasi shu bilan
+ yopiladi (Tugma standarti — "button", 18/#31) */}
+ <Tugma type="submit" value="bekor">
+ Bekor qilish
+ </Tugma>
+ <Tugma type="submit" value="ochir" variant="xavfli">
O'chirish
- </button>
+ </Tugma>Bu — eng qiziq joy. v7 da tugmalar type siz edi va bu ataylab: <form method="dialog"> ichida submit tugma dialogni yopadi va returnValue ga o'z value sini yozadi (dialog). Tugma ning standarti "button" — u bilan dialog yopilmay qolardi. Shuning uchun kanon type="submit" ni aniq yozdi va izohda sababini qoldirdi. "Xavfsiz standart" qoidasining ikkinchi tomoni: xavfli xulq kerak bo'lgan joyda u ko'rinib tursin.
Qolgan oltitasi: AmalTugmasi (har qatordagi «Bajarildi», «O'chirish», «Tahrirlash» — ref bilan), Eksport.tsx (ikki tugma), Import.tsx (type="submit"). Brauzer tekshiruvi 159/159 — ssenariy hech qayerda o'zgarmadi. Tashqi xulq o'sha, faqat ichki tuzilma o'zgardi — bu refaktorlash.
7.3 Nega Tugma polymorphic emas?
#29 dagi as va asChild bu yerda yo'q. vazifalar da tugma ko'rinishidagi havola yo'q, demak polymorphic API — hech kim ishlatmaydigan murakkablik. Kerak bo'lgan kuni qo'shiladi va bu buzuvchi o'zgarish emas: yangi ixtiyoriy props. «API tekshiruv ro'yxati» dagi oxirgi qator shu: kam props bilan boshlash va kerak bo'lganda qo'shish. Bu tamoyil YAGNI deb ham ataladi ("You Aren't Gonna Need It" — "bu sizga kerak bo'lmaydi").
8. Ko'p uchraydigan xatolar
| Belgi | Sabab | Davosi |
|---|---|---|
| Ikki "zid" props birga berildi, natija tasodifiy | boolean'lar to'plami | bitta variant union |
aria-label, id ishlamaydi |
komponent faqat o'z props'ini oladi | ComponentPropsWithoutRef + ...rest |
| Komponent stili yo'qoldi | foydalanuvchi className i ustidan yozdi |
className ni birlashtiring |
| Tugma bosilsa forma yuboriladi | <button> standarti — submit |
type="button" standart |
| Dialog tugmasi uni yopmaydi | standart type="button" |
method="dialog" da type="submit" aniq |
variant="qizil" — rang nomi |
ko'rinish nomi ma'no emas, rang | ma'no: xavfli, asosiy |
9. Mashqlar
Mashqlar kurs/mashqlar/18/31-komponent-api/ da. Har yechimni «Ishga tushir» bilan sinang.
1-mashq (oson): nomlarni tuzating
Har props uchun to'g'ri nomni yozing:
isDisabled→clickHandler→kind="danger"(boshqa komponentlardavariant) →text="Saqlash"(tugma matni) →
Yechim
Native nom bor — disabled. Hodisa props'i — on + hodisa: onClick. Loyihada ko'rinish variant deb atalsa, hamma komponentda shunday — izchillik. Kontent props emas, children: <Tugma>Saqlash</Tugma> («Props nomlash» jadvali).
2-mashq (o'rta): Badge — boolean'lardan variantga
«Bahor» menyusida taom yonidagi belgi: <Badge isNew>, <Badge isSpicy>, <Badge isVegan>. Ikkitasi birga berilsa, nima chiqishi noaniq. Badge ni variant ("yangi" | "achchiq" | "vegan") bilan qayta yozing. Matn — children, className qo'shilsin, qolgan atributlar <span> ga o'tsin. Klass: badge badge-yangi kabi.
Kutilgan natija:
Osh yangi
Lag'mon achchiqYechim
import { useEffect } from "react";
function Badge({ variant, className, ...rest }) {
const base = `badge badge-${variant}`;
return (
<span
className={
className === undefined ? base : `${base} ${className}`
}
{...rest}
/>
);
}
function App() {
useEffect(() => {
for (const b of document.querySelectorAll(".badge")) {
console.log(b.className, b.title);
}
}, []);
return (
<ul>
<li>
Osh <Badge variant="yangi">yangi</Badge>
</li>
<li>
Lag'mon{" "}
<Badge
variant="achchiq"
className="katta"
title="Achchiq taom"
>
achchiq
</Badge>
</li>
</ul>
);
}Konsolda:
badge badge-yangi
badge badge-achchiq katta Achchiq taomEkranda:
Osh yangi
Lag'mon achchiqvariant — bitta qiymat, ziddiyat imkonsiz. className="katta" qo'shildi, badge saqlandi. title — Badge uni bilmaydi, ...rest orqali <span> ga o'tdi. Birinchi qator oxiridagi bo'sh joy — title yo'q (bo'sh satr). Matn children da: belgini boshqa tilga tarjima qilish yoki ikonka qo'shish uchun Badge ga tegish shart emas.
3-mashq (qiyin): TextField API'si
TextField komponentini loyihalang: label (majburiy matn), error (ixtiyoriy matn), qolgan hamma narsa — <input> atributlari. Talablar: id — useId bilan avtomatik (useId), lekin foydalanuvchi id bersa — uniki; error bo'lsa, aria-invalid="true" va aria-describedby xato matniga ulansin. App da ikki maydon: biri xatosiz, biri error="Telefon raqami noto'g'ri" bilan. Effektda ikkinchi input'ning aria-describedby si xato matni elementiga ishora qilishini tekshiring.
Ishora: label va error — komponentning o'z qarorlari (props), qolgani — ...rest. Native maydon atributlari — Formalar I.
Kutilgan natija:
xato bog'langan: trueYechim
import { useEffect, useId } from "react";
function TextField({ label, error, id, ...rest }) {
const autoId = useId();
const inputId = id ?? autoId;
const errorId = `${inputId}-xato`;
return (
<p>
<label htmlFor={inputId}>{label}</label>{" "}
<input
id={inputId}
aria-invalid={error ? true : undefined}
aria-describedby={error ? errorId : undefined}
{...rest}
/>
{error && <span id={errorId}> {error}</span>}
</p>
);
}
function App() {
useEffect(() => {
const input = document.getElementById("telefon");
const target = document.getElementById(
input.getAttribute("aria-describedby"),
);
const linked = target?.textContent.trim() !== "";
console.log("xato bog'langan:", linked);
}, []);
return (
<form>
<TextField label="Ism" name="ism" />
<TextField
label="Telefon"
id="telefon"
type="tel"
defaultValue="+998"
error="Telefon raqami noto'g'ri"
/>
</form>
);
}Konsolda:
xato bog'langan: trueEkranda:
Ism
Telefon Telefon raqami noto'g'riAPI'da faqat ikki o'z props'i — label va error. name, type, defaultValue — native, o'rganish shart emas. id — "xavfsiz standart": bermasangiz ham label input'ga bog'lanadi; bersangiz — sizniki (id ?? autoId). aria-invalid va aria-describedby ...rest dan oldin — foydalanuvchi ularni o'zgartira oladi. Bu ham qaror: masalan, u qo'shimcha tavsif matnini ulamoqchi bo'lishi mumkin. Xatoni o'chirib bo'lmaydigan qilmoqchi bo'lsangiz, tartibni almashtiring (#30 dagi getter qoidasi).
4-mashq: vazifalar qadami
refactor/tugma-tokenlar branch'ida src/ui/Tugma.tsx ni yarating va «To'qqiz joyga» bo'limidagidek almashtiring. CSS'da .xavfli ni .tugma[data-variant=…] ga o'zgartiring. Dialog tugmalariga type="submit" ni unutmang. npm test, npm run tip, npm run lint toza bo'lsin; brauzerda o'chirish dialogini sinab ko'ring. Commit — #33 da.
Yechim
Eng muhim tekshiruv — dialog: vazifani o'chirib ko'ring. «O'chirish» va «Bekor qilish» dialogni yopishi va to'g'ri javob berishi kerak. type="submit" unutilsa, tugma bosiladi, lekin dialog ochiq qoladi va konsolda xato yo'q — jim regressiya. Brauzer tekshiruvi (e2e) buni ushlaydi: o'chirish ssenariysi muvaffaqiyatsiz bo'ladi. grep -rn "<button" src/komponentlar — qolgan oddiy tugmalarni topish uchun. TemaTanlov va qator ichidagi katak — tugma emas yoki boshqa ko'rinishli: ularni o'z holida qoldiring.
10. Real ishda
- Dizayn tizimi komponentlari: shadcn/ui
Button(variant,size,asChild), MUI (variant,color,size), Chakra — hammasi union props va native atributlarni uzatish. Bu darsdagi qoidalar ularning hujjatlarida "API guidelines" bo'limida yoziladi. - Kod ko'rigi: "yangi boolean props" — PR'larda ko'p muhokama qilinadigan mavzu: "bu variant emasmi?", "kompozitsiya bilan bo'lmaydimi?".
- Kutubxona yozish: API — ommaviy shartnoma; props'ni olib tashlash — major versiya. Storybook'da har variant alohida hikoya (story) bo'ladi (Storybook).
- Intervyu savollari: "Yaxshi komponent API'si qanday bo'ladi?", "Boolean prop portlashi nima?", "Nega
classNameni birlashtirasiz?", "ComponentProps<'button'>nima beradi?".
Xulosa
- Props nomlari — DOM va React odatlari bo'yicha: native nom,
on…hodisa, ijobiy boolean, kontent —children, izchil lug'at. - Bir-birini istisno qiladigan ko'rinish props'lari — bitta union (
variant); boolean'lar to'plami 2ⁿ holat va jim ziddiyat beradi. - Native atributlar uchun
ComponentPropsWithoutRef<"button">+...rest;classNamebirlashtiriladi;ref— oddiy props. - Standart qiymatlar xavfsiz (
type="button"), xavfli xulq aniq yoziladi (type="submit"). - Kompozitsiya konfiguratsiyadan yaxshi: ikonka va matn —
children, props — faqat komponentning o'z qarorlari. vazifalarholat 33:Tugma—variant→data-variant, 9 joyda, dialogdatype="submit"aniq.
Keyingi dars: Katta frontend loyiha arxitekturasi — xususiyat papkalari, qatlamlar, ochiq API (index.ts) va import qoidalari.
Manbalar
- React: "Passing Props to a Component" — react.dev/learn/passing-props-to-a-component
- React TypeScript Cheatsheet: "ComponentProps" — react-typescript-cheatsheet.netlify.app
- MDN:
<button>typeatributi — developer.mozilla.org/docs/Web/HTML/Element/button - Radix: "Styling" (
data-stateatributlari) — radix-ui.com/primitives/docs/guides/styling - Kanon:
sinov/18/QADAMLAR.md(#31–#33),holatlar/33/src/ui/Tugma.tsx
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!