IlmHamroh
JavaScript Full-stack/17-qism. React asoslari6/45-dars20 daqiqa
Mundarija (32)

Props: komponentga ma'lumot uzatish — destructuring, default qiymat, spread va funksiya props

Qisqacha: Props — ota komponent bolaga beradigan qiymatlar: <MenuCard name="Osh" price={35000} />. React ularni bitta obyektga yig'ib, komponentga birinchi argument qilib beradi. Odatda parametrdayoq ajratib olinadi: function MenuCard({ name, price, currency = "so'm" }). Props faqat o'qiladi: komponent ularni o'zgartirmaydi, React dev rejimda bu obyektni muzlatib qo'yadi. Qiymat sifatida istalgan narsa — satr, son, boolean, obyekt, hatto funksiya ham berilishi mumkin.

Bu darsda

  • Komponentga props berasiz va uni parametrda destructuring bilan olasiz.
  • Satr va {} dagi qiymat farqini, default qiymat va boolean props'ni bilasiz.
  • Props nega faqat o'qilishini va uni o'zgartirmoqchi bo'lsa nima bo'lishini ko'rasiz.
  • {...props} spread bilan props uzatasiz va uning tuzog'ini taniysiz.
  • Props'ga TypeScript turi yozasiz va uchta eng ko'p uchraydigan tip xatosini o'qiysiz.

Oldin bilishingiz kerak: Komponentlar: yaratish, nomlash va fayllarga ajratish, Parametrda destructuring va options obyekti, Spread va rest operatori.

1. Nega bu kerak?

Oldingi dars mashqida MenuCard uch marta chiqdi — uchalasida ham "Osh — 35000 so'm". Komponent bitta, taom esa har xil bo'lishi kerak. Har taomga alohida OshCard, MantiCard yozish — nusxa ko'chirish, ya'ni xato manbai.

Vanilla'da bu muammoni funksiya argumentlari bilan yechardik. vazifalar dagi tugmaYasa(amal, matn, nomi) bitta funksiya, lekin har chaqiruvda boshqa tugma yasaydi: "Tahrirlash", "O'chirish", "Saqlash". Parametrlar va argumentlar darsidagi g'oya.

React'da argumentlarning nomi — props (properties — "xususiyatlar"). Ularni HTML atributi kabi yozasiz. Hayotiy o'xshatish: oshxonadagi buyurtma varaqasi. Oshpaz bitta retsept bilan ishlaydi, varaqada esa "osh, 2 porsiya, piyozsiz" deb yozilgan. Retsept — komponent, varaqa — props.

2. Props qanday uzatiladi

2.1 Bitta obyekt

Props atributlar kabi yoziladi va React ularni bitta obyektga yig'adi. Komponent uni birinchi argument qilib oladi:

jsx
function MenuCard(props) {
  console.log(props);
  return (
    <li>
      {props.name} — {props.price} so'm
    </li>
  );
}

function App() {
  return (
    <ul>
      <MenuCard name="Osh" price={35000} />
    </ul>
  );
}

Konsolda:

text
{name: 'Osh', price: 35000}

Ekranda:

text
Osh — 35000 so'm

JSX I darsida ko'rgandik: <MenuCard name="Osh" price={35000} /> → jsx(MenuCard, { name: "Osh", price: 35000 }). Ikkinchi argument — o'sha obyekt. React komponentni chaqirganda uni props parametriga beradi.

2.2 Parametrda destructuring

Har safar props. yozish noqulay. Odatda obyekt parametrdayoq ajratib olinadi (parametrda destructuring):

jsx
function MenuCard({ name, price }) {
  return (
    <li>
      {name} — {price} so'm
    </li>
  );
}

function App() {
  return (
    <ul>
      <MenuCard name="Osh" price={35000} />
      <MenuCard name="Lag'mon" price={28000} />
      <MenuCard name="Manti" price={30000} />
    </ul>
  );
}

Ekranda:

text
Osh — 35000 so'm
Lag'mon — 28000 so'm
Manti — 30000 so'm

Bitta funksiya — uch xil karta. Parametr qatoridan komponent nimani kutishi ham darhol ko'rinadi: name va price. Kursda va vazifalar da hamma joyda shu shakl.

2.3 Qo'shtirnoq yoki jingalak qavs

Qo'shtirnoqdagi qiymat — har doim satr. Son, boolean, obyekt yoki o'zgaruvchi kerak bo'lsa — {}:

jsx
function PriceTest({ price }) {
  return (
    <p>
      {typeof price}: {price + 5000}
    </p>
  );
}

function App() {
  return (
    <div>
      <PriceTest price="35000" />
      <PriceTest price={35000} />
    </div>
  );
}

Ekranda:

text
string: 350005000
number: 40000

Birinchisida "35000" + 5000 — satrga satr ulandi (Yashirin coercion darsidagi tuzoq). Xato chiqmadi, faqat noto'g'ri son. TypeScript buni ushlaydi — «Props'ga tur yozamiz» bo'limida ko'ramiz.

Tekshirib ko'ring: <MenuCard name={"Osh"} /> va <MenuCard name="Osh" /> farqi bormi? <MenuCard dish={{ name: "Osh" }} /> dagi ikki juft qavs nima?

Javob

Birinchi juftlikda farq yo'q — ikkalasi ham satr. Satr uchun qo'shtirnoq qisqaroq. Ikki juft qavs: tashqisi — "bu yerda JavaScript", ichkisi — obyekt literali. Ya'ni dish ga { name: "Osh" } obyekti beriladi. JSX I dagi style={{ … }} ham aynan shunday edi.

3. Default qiymat va boolean props

3.1 Berilmagan prop — undefined

Ota komponent ba'zi props'ni bermasligi mumkin. Unda u undefined bo'ladi. Destructuring'dagi default qiymat shu holat uchun:

jsx
function Price({ value = 0, currency = "so'm" }) {
  return (
    <p>
      {value} {currency}
    </p>
  );
}

function App() {
  return (
    <div>
      <Price value={35000} />
      <Price value={5} currency="$" />
      <Price />
    </div>
  );
}

Ekranda:

text
35000 so'm
5 $
0 so'm

Default faqat undefined da ishlaydi (Obyekt destructuring dagi qoida). value={null} bersangiz — default olinmaydi, null esa ekranda hech narsa chizmaydi. Shuning uchun "qiymat yo'q" holatini undefined (ya'ni prop'ni umuman yozmaslik) bilan bildirish qulay.

3.2 Boolean props

Qiymatsiz yozilgan atribut — true:

jsx
function MenuCard({ name, isNew = false, soldOut = false }) {
  return (
    <li>
      {name}
      {isNew && " · Yangi!"}
      {soldOut && " · Tugadi"}
    </li>
  );
}

function App() {
  return (
    <ul>
      <MenuCard name="Manti" isNew />
      <MenuCard name="Somsa" soldOut={true} />
      <MenuCard name="Osh" isNew={false} />
    </ul>
  );
}

Ekranda:

text
Manti · Yangi!
Somsa · Tugadi
Osh

isNew — isNew={true} ning qisqa shakli, HTML'dagi disabled kabi. Boolean props nomi odatda savolga o'xshaydi: isNew, soldOut, hasDiscount. Bu yerda && chapida — haqiqiy boolean. Shuning uchun JSX II dagi 0 tuzog'i yo'q.

4. Props faqat o'qiladi

4.1 O'zgartirishga urinish

Sardor narxni chegirma bilan ko'rsatmoqchi bo'ldi va props'ning o'zini o'zgartirdi:

jsx
function MenuCard(props) {
  props.price = props.price * 0.9; // ❌ 10% chegirma
  return (
    <li>
      {props.name} — {props.price} so'm
    </li>
  );
}

function App() {
  return <MenuCard name="Osh" price={35000} />;
}

Konsolda:

text
Uncaught TypeError: Cannot assign to read only property 'price' of object '#<Object>'

"Faqat o'qiladigan price xususiyatiga yozib bo'lmaydi." Saytda «Komponentni chizishda xato» qutisi chiqadi: Komponentlar: App → MenuCard. React dev rejimda props obyektini Object.freeze bilan muzlatadi. Modul kodi esa JavaScript'ning strict mode ida ishlaydi (React'ning StrictMode komponenti bilan adashtirmang) — muzlatilgan obyektga yozish jim o'tmaydi, xato tashlaydi.

To'g'ri yo'l — yangi lokal o'zgaruvchi:

jsx
function MenuCard({ name, price }) {
  const salePrice = price * 0.9;
  return (
    <li>
      {name} — {salePrice} so'm
    </li>
  );
}

function App() {
  return <MenuCard name="Osh" price={35000} />;
}

Ekranda:

text
Osh — 31500 so'm

Production build'da React props'ni muzlatmaydi — tezlik uchun. Xato tashlanmaydi, lekin kod baribir noto'g'ri. Linter ikkala holatda ham ushlaydi. eslint-plugin-react-hooks 7.1.1 (react-hooks/immutability qoidasi, chiqish qisqartirilgan):

text
  2:3  error  Error: This value cannot be modified

Modifying component props or hook arguments is not allowed. Consider using a local variable instead.

"Komponent props'ini yoki hook argumentlarini o'zgartirib bo'lmaydi. O'rniga lokal o'zgaruvchi ishlating."

4.2 Nega bunday qoida

Props — ota komponentning ma'lumoti. Bola uni faqat o'qiydi, xuddi ofitsiant buyurtma varaqasini o'qiganidek. Ofitsiant varaqadagi "2 porsiya" ni o'chirib "3" deb yozsa — oshxona chalkashadi. React'da ham shunday: props o'zgarsa, React buni bilmaydi va ekran ma'lumotdan ajralib qoladi.

Props'ni ota o'zgartiradi — yangi qiymat bilan qayta chizib. Quyidagi blokda ota (vanilla draw()) har bosishda MenuCard ga boshqa taom beradi. Blok tugmani ikki marta o'zi bosadi:

jsx
import { createRoot } from "react-dom/client";

const dishes = [
  { name: "Osh", price: 35000 },
  { name: "Lag'mon", price: 28000 },
  { name: "Manti", price: 30000 },
];
const root = createRoot(document.getElementById("root"));
let index = 0;

function MenuCard({ name, price }) {
  console.log("MenuCard chizildi:", name);
  return <p>{name} — {price} so'm</p>;
}

function draw() {
  const dish = dishes[index];
  root.render(
    <div>
      <MenuCard name={dish.name} price={dish.price} />
      <button onClick={() => {
        index = (index + 1) % dishes.length;
        draw();
      }}>
        Keyingi taom
      </button>
    </div>
  );
}
draw();

Konsolda:

text
MenuCard chizildi: Osh
MenuCard chizildi: Lag'mon
MenuCard chizildi: Manti

Ekranda:

text
Manti — 30000 so'm
Keyingi taom
Qadam Ota beradi (props) Ekranda
birinchi chizish {name: "Osh", price: 35000} Osh — 35000 so'm
«Keyingi taom» {name: "Lag'mon", price: 28000} Lag'mon — 28000 so'm
«Keyingi taom» {name: "Manti", price: 30000} Manti — 30000 so'm

MenuCard hech narsani o'zgartirmadi — har safar yangi props bilan qayta chaqirildi.

flowchart TD
  P["Ota: draw()"] -- "props: name, price" --> C["MenuCard"]
  C -- "JSX" --> E["Ekran"]
  C -. "o'zgartira olmaydi" .-> P

Diagrammaga qarang: props faqat bir yo'nalishda — otadan bolaga oqadi. Bola ekranni yasaydi, lekin otaning ma'lumotiga tega olmaydi (punktir). Bu UI = f(state) ning kichik nusxasi: komponent — props'dan ekran yasaydigan funksiya. Ma'lumot faqat yuqoridan pastga oqadi.

Tekshirib ko'ring: function Badge({ text }) { text = text.toUpperCase(); return <b>{text}</b>; } — bu ham props'ni o'zgartirishmi? Xato chiqadimi?

Javob

Yo'q, xato chiqmaydi. text — destructuring yaratgan lokal o'zgaruvchi, props obyektining o'zi emas. Unga yangi qiymat yozish props'ga tegmaydi. Lekin o'qishga qulayroq yo'l — yangi nom: const upper = text.toUpperCase();. Shunda "kelgan qiymat" va "hisoblangan qiymat" chalkashmaydi.

5. Spread: {...props}

5.1 Obyektni props qilib yoyish

Ma'lumot ko'pincha tayyor obyekt bo'lib keladi. Uni maydonma-maydon yozish o'rniga spread bilan yoyish mumkin:

jsx
const dish = { name: "Manti", price: 30000, isNew: true };

function MenuCard({ name, price, isNew }) {
  return (
    <li>
      {name} — {price} so'm{isNew && " · Yangi!"}
    </li>
  );
}

function App() {
  return (
    <ul>
      <MenuCard {...dish} />
      <MenuCard {...dish} price={27000} />
    </ul>
  );
}

Ekranda:

text
Manti — 30000 so'm · Yangi!
Manti — 27000 so'm · Yangi!

{...dish} = name="Manti" price={30000} isNew={true}. Tartib muhim: keyingisi oldingisini ustidan yozadi, obyekt spread'dagidek. Ikkinchi kartada price={27000} spread'dan keyin turibdi — shuning uchun u yutdi.

5.2 Qolganini uzatish: ...rest

Rest bilan "keraklisini olib, qolganini uzatish" mumkin. Masalan, umumiy tugma komponenti. U label ni o'zi ishlatadi, qolgan atributlarni esa <button> ga beradi:

jsx
function ActionButton({ label, ...rest }) {
  return (
    <button type="button" {...rest}>
      {label}
    </button>
  );
}

function App() {
  return (
    <div>
      <ActionButton label="Saqlash" title="Ctrl+S" />
      <ActionButton label="Yuborish" type="submit" />
      <ActionButton label="Tugadi" disabled />
    </div>
  );
}

Ekranda:

text
SaqlashYuborishTugadi

title, type, disabled — ActionButton ularni bilmaydi ham, faqat uzatadi. type="button" spread'dan oldin turibdi — bu standart qiymat: kerak bo'lsa, chaqiruvchi type="submit" bilan almashtiradi.

5.3 Tuzoq: DOM'ga begona prop tushadi

Hamma narsani ko'r-ko'rona uzatish — xavfli:

jsx
function MenuCard(props) {
  return <li {...props}>Manti</li>;
}

function App() {
  return (
    <ul>
      <MenuCard isNew />
    </ul>
  );
}

Konsolda:

text
React does not recognize the `isNew` prop on a DOM element. If you intentionally want it to appear in the DOM as a custom attribute, spell it as lowercase `isnew` instead. If you accidentally passed it from a parent component, remove it from the DOM element.

Ekranda:

text
Manti

"React DOM elementidagi isNew prop'ini tanimaydi. Ataylab DOM'da maxsus atribut bo'lishini istasangiz — kichik harf bilan isnew yozing. Ota komponentdan tasodifan o'tib kelgan bo'lsa — uni DOM elementidan olib tashlang." isNew komponent uchun edi, <li> uchun emas. Qoida: o'zingiz ishlatadigan props'ni destructuring bilan ajrating, <li> ga faqat ...rest ni bering.

Tekshirib ko'ring: <ActionButton label="Saqlash" type="submit" /> da ActionButton ichida {...rest} type="button" deb yozilgan bo'lsa (spread oldin), tugma turi qanday bo'ladi?

Javob

"button". Keyin yozilgan atribut yutadi: spread type="submit" ni qo'ydi, keyingi type="button" uni ustidan yozdi. Chaqiruvchi endi turni o'zgartira olmaydi. Standart qiymat spread'dan oldin, majburiy qiymat esa keyin yoziladi.

6. Maxsus props: key va ref

6.1 key komponentga yetib bormaydi

Ikkita atribut React'ning o'ziga tegishli. Ulardan biri — key (JSX II da ro'yxatda ko'rgandik). U props obyektiga kirmaydi:

jsx
function MenuCard(props) {
  console.log(props, props.key);
  return <li>{props.name}</li>;
}

function App() {
  return (
    <ul>
      <MenuCard key="osh" name="Osh" />
    </ul>
  );
}

Konsolda:

text
MenuCard: `key` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://react.dev/link/special-props)
{name: 'Osh'} undefined

Ekranda:

text
Osh

"MenuCard: key — prop emas. Uni o'qishga urinish undefined qaytaradi. Bola komponentga shu qiymat kerak bo'lsa — uni boshqa nom bilan alohida prop qilib bering." key — React uchun yorliq: "bu qaysi element?". Komponentga esa u kerak emas. Id kerak bo'lsa — ikki marta bering: <MenuCard key={dish.id} id={dish.id} />. Buning sababini Ro'yxatlar va key darsida ko'ramiz.

6.2 ref — React 19 da oddiy prop

Ikkinchi maxsus atribut — ref, DOM elementiga to'g'ridan-to'g'ri murojaat uchun. React 18 gacha u ham props'ga kirmasdi va buning uchun forwardRef degan maxsus funksiya kerak edi. React 19 dan boshlab ref komponentga oddiy prop bo'lib keladi. Eski kodda forwardRef ni ko'rasiz — uni useRef II: DOM elementlari va ref prop darsida o'rganamiz.

6.3 Props nomlari

Nima Qoida Misol
oddiy qiymat camelCase, ot name, price, dishName
boolean savol shaklida isNew, soldOut, hasDiscount
hodisa (funksiya) on + fe'l onOrder, onDelete
HTML atributi nomi DOM'dagidek className, htmlFor, disabled

class, for kabi JavaScript kalit so'zlarini prop nomi qilmang — JSX I dagi className sababi shu. key va ref nomlari ham band.

7. Funksiya ham prop

Props'ga istalgan qiymat beriladi — funksiya ham. Masalan, narxni qanday ko'rsatishni ota hal qilsin:

jsx
function PriceTag({ price, format = (n) => `${n} so'm` }) {
  return <p>Narx: {format(price)}</p>;
}

function App() {
  return (
    <div>
      <PriceTag price={35000} />
      <PriceTag
        price={35000}
        format={(n) => `${n / 1000} ming so'm`}
      />
    </div>
  );
}

Ekranda:

text
Narx: 35000 so'm
Narx: 35 ming so'm

Bu callback g'oyasi. PriceTag funksiyani o'zi tanlamaydi — tashqaridan oladi. Eng ko'p ishlatiladigan funksiya props — hodisalar: onClick, onChange. "Tugma bosilganda nima qilish" ni bola emas, ota biladi. Ularni Hodisalarni boshqarish darsida yozamiz.

8. Props'ga tur yozamiz

vazifalar — TypeScript'da. Props ham turi bilan yoziladi:

tsx
type MenuCardProps = {
  name: string;
  price: number;
  isNew?: boolean; // ? — ixtiyoriy
};

function MenuCard({ name, price, isNew = false }: MenuCardProps) {
  return (
    <li>
      {name} — {price} so'm{isNew && " · Yangi!"}
    </li>
  );
}

export default function App() {
  return (
    <ul>
      <MenuCard name="Manti" price={30000} isNew />
    </ul>
  );
}

Ekranda:

text
Manti — 30000 so'm · Yangi!

type — obyekt turlari darsidagidek. Endi uchta ko'p uchraydigan xato kompilyatsiyadayoq ushlanadi:

tsx
type MenuCardProps = {
  name: string;
  price: number;
  isNew?: boolean;
};

function MenuCard({ name, price, isNew = false }: MenuCardProps) {
  return <li>{name} {price} {isNew && "Yangi"}</li>;
}

export function App() {
  return (
    <ul>
      <MenuCard name="Osh" />
      <MenuCard name="Manti" price="30000" />
      <MenuCard name="Choy" price={5000} prise={5000} />
    </ul>
  );
}

Xato:

text
TS2741: Property 'price' is missing in type '{ name: string; }' but required in type 'MenuCardProps'.
TS2322: Type 'string' is not assignable to type 'number'.
TS2322: Type '{ name: string; price: number; prise: number; }' is not assignable to type 'IntrinsicAttributes & MenuCardProps'.
  Property 'prise' does not exist on type 'IntrinsicAttributes & MenuCardProps'. Did you mean 'price'?

Uchala xato tarjimasi:

  1. TS2741 — "price xususiyati { name: string; } da yo'q, lekin MenuCardProps da majburiy." Prop unutilgan.
  2. TS2322 — "string turini number ga berib bo'lmaydi." Bu — «Qo'shtirnoq yoki jingalak qavs» bo'limidagi "350005000" xatosi, endi ishga tushmasdan ushlandi.
  3. TS2322 — "prise xususiyati … turida yo'q. price demoqchimidingiz?" Imlo xatosi. IntrinsicAttributes — React har komponentga qo'shadigan maxsus props (masalan, key).

Props turlarining chuqur tomonlari (children turi, ComponentProps<"button">, generic) — React + TS I: props va children turlari darsida.

Tekshirib ko'ring: isNew?: boolean dan ? ni olib tashlasak, <MenuCard name="Osh" price={35000} /> qatori nima bo'ladi? isNew = false default qiymati endi kerakmi?

Javob

? siz isNew majburiy bo'ladi — prop'siz qator TS2741: Property 'isNew' is missing … beradi. Har chaqiruvda isNew={false} yozishga to'g'ri keladi. Default qiymat esa ma'nosini yo'qotadi: majburiy prop hech qachon undefined bo'lmaydi. Qoida: ko'p joyda bir xil qiymat bo'ladigan prop — ixtiyoriy va default bilan, har doim har xil bo'ladigani — majburiy.

9. Vazifalar qadami: AmalTugmasi

refactor/royxat-react branch'ida birinchi komponentni yozamiz. v6 dagi tugmaYasa() ni eslang:

ts
function tugmaYasa(
  amal: Amal,
  matn: string,
  nomi: string,
): HTMLButtonElement {
  const tugma = document.createElement("button");
  tugma.type = "button";
  tugma.dataset.amal = amal;
  tugma.textContent = matn;
  tugma.setAttribute("aria-label", `${matn}: ${nomi}`);
  return tugma;
}

Uch argument — uchta prop. Yangi fayl src/AmalTugmasi.tsx:

tsx
// AmalTugmasi.tsx — qatordagi tugma (17/#06: props). Ekran
// o'quvchi "Tahrirlash" emas, "Tahrirlash: Non olish" eshitadi —
// qaysi vazifa ekani aria-label'da
export type Amal =
  "almashtir" | "ochir" | "tahrirla" | "saqla" | "bekor";

type Props = {
  amal: Amal;
  matn: string; // tugmada ko'rinadigan so'z
  nomi: string; // vazifa matni
};

export function AmalTugmasi({ amal, matn, nomi }: Props) {
  return (
    // data-amal — vanilla hodisa tinglovchisi shunga qaraydi
    // (#11 gacha)
    <button
      type="button"
      data-amal={amal}
      aria-label={`${matn}: ${nomi}`}
    >
      {matn}
    </button>
  );
}

Qatorma-qator:

  • Amal — literal turlar birlashmasi: amal faqat beshta so'zdan biri. amal="ochirish" yozilsa, tsc darhol aytadi. render.ts dagi Amal turi shu faylga ko'chdi.
  • aria-label={`${matn}: ${nomi}`} — template literal props ichida, {} bilan. Malika ekran o'quvchida tugmani "O'chirish: Non olish" deb eshitadi. Faqat "O'chirish" — qaysi vazifa ekani noma'lum (Dinamik UI'da qulaylik).
  • data-amal={amal} — vanilla'dagi dataset.amal. JSX'da data-* atributlari aynan HTML'dagidek yoziladi, chiziqcha bilan. Bosishni hozircha vanilla delegatsiya ushlaydi (Event delegation) va shu atributga qaraydi. Hodisalarni boshqarish darsida u onClick ga almashadi.
  • type="button" — formada tasodifan "yuborish" bo'lmasin; Bobur Enter bosganda ham.
  • Izoh JSX ichida emas, return ( dan keyin — // izoh <button dan oldin, JavaScript qismida turibdi. JSX ichida izoh {/* … */} bo'lardi (JSX II).

.bind(null, "tahrirla", "Tahrirlash") bilan yasalgan to'rtta yordamchi (tahrirTugmasi va boshqalar) endi kerak emas. Ularning o'rnida JSX'da props bilan yozamiz: <AmalTugmasi amal="tahrirla" matn="Tahrirlash" nomi={vazifa.matn} />.

Tekshiruv: npm run tip jim tugaydi. Komponent hali hech qayerda ishlatilmayapti — ekranda hech narsa o'zgarmadi. U children va Shartli render darslarida qatorlarga qo'yiladi. Commit — Ro'yxatlar va key darsida.

10. Ko'p uchraydigan xatolar

Belgi Sabab Davosi
350005000 kabi son price="35000" — satr price={35000}
read only property props'ga yozish lokal o'zgaruvchi
does not recognize the … prop {...props} DOM elementiga o'zingiznikini ajrating, ...rest
default ishlamadi prop null berildi prop'ni yozmang (undefined)
TS2741 … is missing majburiy prop berilmagan bering yoki ? qiling
`key` is not a prop bolada props.key o'qilgan alohida prop: id={…}
Did you mean 'price'? prop nomida imlo xatosi nomni tuzating

11. Mashqlar

Mashqlar kurs/mashqlar/17/06-props/ da. Har yechimni «Ishga tushir» bilan sinang.

1-mashq (oson): ekranda nima chiqadi?

Kodni ishga tushirmasdan oldin har qatorni ayting.

jsx
function Line({ label, count = 1, unit = "porsiya" }) {
  return (
    <p>
      {label}: {count + 1} {unit}
    </p>
  );
}

function App() {
  return (
    <div>
      <Line label="A" count={2} />
      <Line label="B" count="2" />
      <Line label="C" />
      <Line label="D" count={0} unit="ta" />
    </div>
  );
}
  • B qatorida, B: dan keyin:
  • C qatorida, C: dan keyin:
Yechim

Ekranda:

text
A: 3 porsiya
B: 21 porsiya
C: 2 porsiya
D: 1 ta

A — son, 2 + 1. B — qo'shtirnoq, satr: "2" + 1 → "21". C — count berilmagan, default 1 ishladi. D — 0 berilgan, default ishlamaydi (0 — undefined emas), 0 + 1 → 1.

2-mashq (o'rta): menyu kartasi

MenuCard komponentini yozing. Props: name, price, isNew (boolean, default false), currency (default "so'm"). Yangi taomda nomdan keyin " · Yangi!" chiqsin. App to'rtta karta chizsin: osh (35000), manti (30000, yangi), ko'k choy (5000) va lag'mon (28000). Lag'mon narxi dollarda: price={2.2}, currency="$". Ekranda shunday bo'lsin:

text
Osh — 35000 so'm
Manti · Yangi! — 30000 so'm
Ko'k choy — 5000 so'm
Lag'mon — 2.2 $

Ishora: «Default qiymat va boolean props» bo'limidagi ikkita misolni birlashtiring.

Yechim
jsx
function MenuCard({ name, price, isNew = false, currency = "so'm" }) {
  return (
    <li>
      {name}
      {isNew && " · Yangi!"} — {price} {currency}
    </li>
  );
}

function App() {
  return (
    <ul>
      <MenuCard name="Osh" price={35000} />
      <MenuCard name="Manti" price={30000} isNew />
      <MenuCard name="Ko'k choy" price={5000} />
      <MenuCard name="Lag'mon" price={2.2} currency="$" />
    </ul>
  );
}

Ekranda:

text
Osh — 35000 so'm
Manti · Yangi! — 30000 so'm
Ko'k choy — 5000 so'm
Lag'mon — 2.2 $

{isNew && " · Yangi!"} va — {price} orasidagi qator ko'chishi — JSX uni bitta bo'shliqqa aylantiradi (JSX I). Shuning uchun nomdan keyin " — " to'g'ri chiqdi.

3-mashq (qiyin): buyurtma qatori (TypeScript)

OrderLine komponentini .tsx da yozing. Props turi:

  • dish — { name: string; price: number } obyekti;
  • count — son;
  • formatPrice — ixtiyoriy funksiya (n: number) => string, default — (n) => `${n} so'm`;
  • highlighted — ixtiyoriy boolean: true bo'lsa <li> ga className="ajratilgan", aks holda klass yo'q (undefined).

Ekranda: Osh × 2 = 70000 so'm. App uchta qator chizsin: osh × 2 (ajratilgan), manti × 3, ko'k choy × 4 — oxirgisi formatPrice bilan "20 ming so'm" ko'rinishida. Ishora: ixtiyoriy prop — ?: (Obyekt turlari), funksiya turi — Funksiyalarni tiplash.

Yechim
tsx
type Dish = { name: string; price: number };

type OrderLineProps = {
  dish: Dish;
  count: number;
  formatPrice?: (n: number) => string;
  highlighted?: boolean;
};

function OrderLine({
  dish,
  count,
  formatPrice = (n) => `${n} so'm`,
  highlighted = false,
}: OrderLineProps) {
  return (
    <li className={highlighted ? "ajratilgan" : undefined}>
      {dish.name} × {count} = {formatPrice(dish.price * count)}
    </li>
  );
}

export default function App() {
  return (
    <ul>
      <OrderLine
        dish={{ name: "Osh", price: 35000 }}
        count={2}
        highlighted
      />
      <OrderLine dish={{ name: "Manti", price: 30000 }} count={3} />
      <OrderLine
        dish={{ name: "Ko'k choy", price: 5000 }}
        count={4}
        formatPrice={(n) => `${n / 1000} ming so'm`}
      />
    </ul>
  );
}

Ekranda:

text
Osh × 2 = 70000 so'm
Manti × 3 = 90000 so'm
Ko'k choy × 4 = 20 ming so'm

Default funksiyada n ning turi yozilmagan — TypeScript uni formatPrice?: (n: number) => string dan o'zi chiqaradi. className={… ? "ajratilgan" : undefined}: undefined bo'lsa React atributni umuman qo'ymaydi. Bo'sh satr "" bersangiz edi, class="" qolardi.

4-mashq: Vazifalar qadami

src/AmalTugmasi.tsx ni «Vazifalar qadami» bo'limidagidek yozing. npm run tip toza bo'lsin. Keyin sinab ko'ring: faylning oxiriga vaqtinchalik qator qo'shing — const sinov = <AmalTugmasi amal="ochirish" matn="O'chirish" nomi="Non" />;. tsc nima deydi? Sinovdan keyin qatorni o'chiring.

Yechim

tsc amal qiymatini rad etadi — "ochirish" Amal birlashmasida yo'q:

text
TS2322: Type '"ochirish"' is not assignable to type 'Amal'.

Literal tur aynan shu uchun: e2e ssenariy va vanilla tinglovchi data-amal="ochir" ni kutadi. Bitta harf farqi bilan tugma ishlamay qolardi, endi esa kompilyatsiyada ushlanadi. Qolgan tekshiruvlar — branch oxirida, Ro'yxatlar va key darsida.

12. Real ishda

  • Dizayn tizimlari (kompaniyaning umumiy tugma, karta, modal komponentlari) props bilan sozlanadi: <Button variant="primary" size="sm" disabled>. Yaxshi komponent — kam va aniq props (Komponent API'sini loyihalash).
  • ...rest uzatish — kutubxona komponentlarida kundalik naqsh: tugma o'ramlari aria-*, data-*, title ni pastga o'tkazib yuboradi.
  • TypeScript'da props turi — ishda deyarli majburiy. Kod ko'rigida birinchi qaraladi: majburiy va ixtiyoriy props to'g'ri belgilanganmi.
  • Intervyu savollari: "Props va state farqi?" (state — keyingi darslarda), "Bola komponent props'ni o'zgartira oladimi?", "{...props} qanday tuzoqqa olib keladi?".

Xulosa

  • Props — ota bolaga beradigan qiymatlar; React ularni bitta obyektga yig'ib, birinchi argument qilib beradi.
  • Parametrda destructuring: ({ name, price, currency = "so'm" }); default faqat undefined da ishlaydi.
  • Qo'shtirnoq — satr, {} — istalgan JavaScript qiymat; qiymatsiz atribut — true.
  • Props faqat o'qiladi: dev rejimda muzlatilgan, o'zgartirish TypeError beradi; yangi qiymatni ota yangi render bilan beradi.
  • {...obj} va ...rest qulay, lekin DOM elementiga begona prop tushirmang.
  • vazifalar da birinchi komponent — AmalTugmasi: uch argumentli funksiya uch props'li komponentga aylandi.

Keyingi dars: children va kompozitsiya — komponent ichiga boshqa JSX qo'yishni o'rganamiz va vazifalar qatorining <li> qobig'ini yasaymiz.

Manbalar

  • React: "Passing Props to a Component" — react.dev/learn/passing-props-to-a-component
  • React: "Keeping Components Pure" (props faqat o'qiladi) — react.dev/learn/keeping-components-pure
  • React: "Unknown Prop Warning" — react.dev/warnings/unknown-prop
  • eslint-plugin-react-hooks — immutability qoidasi — react.dev/reference/eslint-plugin-react-hooks
Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
Props: komponentga ma'lumot uzatish — destructuring, default qiymat, spread va funksiya props — IlmHamroh