IlmHamroh
JavaScript Full-stack/17-qism. React asoslari7/45-dars18 daqiqa
Mundarija (27)

children va kompozitsiya: React komponentlarini lego kabi yig'ish — slot, wrapper va Card naqshi

Qisqacha: Komponent teglari orasiga yozilgan hamma narsa — matn, element, boshqa komponent — unga children degan prop bo'lib keladi: <Card>…</Card> → function Card({ children }). Komponent uni o'zi xohlagan joyga qo'yadi: <section>{children}</section>. Bir nechta "joy" kerak bo'lsa, JSX'ni oddiy props bilan ham berish mumkin: <Layout header={<Logo />} footer={…}>. React'da komponentlar bir-biridan meros olmaydi (extends yo'q) — ular bir-birining ichiga qo'yiladi. Bu kompozitsiya deyiladi.

Bu darsda

  • children qanday paydo bo'lishini va unda nima bo'lishi mumkinligini bilasiz.
  • Ichiga istalgan narsa qo'yiladigan "o'ram" komponent (Card, Section) yozasiz.
  • Bir nechta slot'li komponent yasaysiz: header, footer props orqali.
  • Nega React merosxo'rlik o'rniga kompozitsiyani tanlaganini tushuntira olasiz.
  • children ga TypeScript turi (ReactNode) yozasiz.

Oldin bilishingiz kerak: Props: komponentga ma'lumot uzatish, JSX II: ifodalar, Fragment va nima ekranga chiqadi.

1. Nega bu kerak?

«Bahor» saytida bir xil ko'rinishdagi "kartochkalar" ko'p. Taom kartasi, aksiya kartasi, aloqa kartasi — hammasida ramka, soya va sarlavha bor. Ichidagisi esa butunlay har xil: birida narx va rasm, birida muddat, birida telefon va xarita.

Props darsida qiymatni atribut bilan berishni o'rgandik. Lekin kartaning ichidagi butun bir bo'lakni — bir nechta paragraf, tugma, ro'yxatni — content="…" atributiga sig'dirish noqulay. Bizga HTML'dagidek yozish kerak: ochuvchi teg, ichida mazmun, yopuvchi teg.

vazifalar da ham shu muammo bor. render.ts dagi oddiyQator() ham, tahrirQatori() ham bir xil boshlanadi: <li> yaratiladi, unga data-id yoziladi, keyin ichiga har xil narsa qo'shiladi. Qobiq bir xil, ichi har xil. Hayotiy o'xshatish: ovqat qutisi (lanchboks). Quti bitta, ichiga bugun osh, ertaga manti solasiz. Quti ichida nima borligini bilmaydi — u faqat o'raydi.

2. children — teglar orasidagi hamma narsa

2.1 Birinchi o'ram

jsx
function Card({ children }) {
  return <section className="card">{children}</section>;
}

function App() {
  return (
    <div>
      <Card>
        <h2>Osh</h2>
        <p>35000 so'm</p>
      </Card>
      <Card>
        <h2>Aksiya</h2>
        <p>Har juma — ko'k choy bepul</p>
      </Card>
    </div>
  );
}

Ekranda:

text
Osh
35000 so'm
Aksiya
Har juma — ko'k choy bepul

<Card> va </Card> orasidagi ikki element Card ga children prop'i bo'lib keldi. Card esa ularni <section> ichiga qo'ydi. DOM'da natija: ikkita <section class="card">, har birining ichida <h2> va <p>.

JSX I darsidagi transpiler chiqishini eslang. <p>Osh</p> → jsx("p", { children: "Osh" }). Teglar orasidagi mazmun har doim children kalitiga tushadi — HTML teglarida ham, sizning komponentingizda ham. Farqi: <p> ning children ini React o'zi chizadi, Card niki esa — siz {children} deb qayerga yozsangiz, o'sha yerda.

2.2 children ichida nima bo'ladi

Turi — teglar orasida nima yozilganiga bog'liq:

jsx
function Show({ children }) {
  console.log(typeof children, Array.isArray(children));
  return <p>[{children}]</p>;
}

function App() {
  return (
    <div>
      <Show>Osh</Show>
      <Show>Osh {35000}</Show>
      <Show>
        <b>Osh</b>
      </Show>
      <Show />
    </div>
  );
}

Konsolda:

text
string false
object true
object false
undefined false

Ekranda:

text
[Osh]
[Osh 35000]
[Osh]
[]
Teglar orasida children
faqat matn satr: "Osh"
bir nechta bo'lak (matn va {}) massiv: ["Osh ", 35000]
bitta element bitta element obyekti
hech narsa (<Show />) undefined

Bu turlarning hammasini React JSX II dagi qoidalar bilan chizadi. Shuning uchun komponent ichida children ning turini tekshirish deyarli hech qachon kerak emas — uni {children} qilib qo'yish yetadi.

2.3 {children} unutilsa

Eng ko'p uchraydigan xato — jim:

jsx
function Card({ title }) {
  return (
    <section>
      <h2>{title}</h2>
    </section>
  );
}

function App() {
  return (
    <Card title="Osh">
      <p>35000 so'm</p>
    </Card>
  );
}

Ekranda:

text
Osh

Narx yo'q, ogohlantirish ham yo'q. children keldi, lekin Card uni hech qayerga qo'ymadi. Komponent o'zi qaytargan narsani chizadi — boshqasini emas. JavaScript'da bu xato jim o'tadi. TypeScript'da esa jim o'tmaydi — buni «children ga tur yozamiz» bo'limida ko'ramiz.

Tekshirib ko'ring: function Box({ children }) { return <div>{children}{children}</div>; } va <Box><b>Osh</b></Box> — ekranda nima chiqadi?

Javob

"OshOsh" — ikkita <b>. children — oddiy qiymat, uni xohlagancha marta ishlatish mumkin. React har o'rin uchun alohida DOM elementi yasaydi. Element obyekti esa bitta: u "buyurtma qog'ozi", DOM elementi emas (JSX I).

3. Props va children birga

3.1 Sarlavha — props, mazmun — children

Qoida oddiy: qisqa qiymat (matn, son) — props'da, katta JSX bo'lagi — children da:

jsx
function Card({ title, children }) {
  return (
    <section className="card">
      <h2>{title}</h2>
      {children}
    </section>
  );
}

function App() {
  return (
    <div>
      <Card title="Osh">
        <p>Choyxona oshi, 1 porsiya</p>
        <p>35000 so'm</p>
      </Card>
      <Card title="Aloqa">
        <p>Tel: +998 90 000 00 00</p>
      </Card>
    </div>
  );
}

Ekranda:

text
Osh
Choyxona oshi, 1 porsiya
35000 so'm
Aloqa
Tel: +998 90 000 00 00

Card sarlavha qayerda turishini va ramkani biladi. Ichida nima borligini esa bilmaydi va bilishi shart emas. Ertaga kartaga rasm yoki tugma qo'shsangiz, Card ga tegmaysiz.

3.2 Bir nechta "slot"

children — bitta joy. Sahifa sxemasida esa joy ko'p: tepada sarlavha, o'rtada mazmun, pastda pastki qism. Har biriga JSX kerak. Yechim: JSX'ni oddiy props bilan berish. Element ham qiymat-ku (JSX II):

jsx
function PageLayout({ header, footer, children }) {
  return (
    <div className="sahifa">
      <header>{header}</header>
      <main>{children}</main>
      <footer>{footer}</footer>
    </div>
  );
}

function App() {
  return (
    <PageLayout
      header={<h1>«Bahor» oshxonasi</h1>}
      footer={<small>07:00–23:00, har kuni</small>}
    >
      <p>Bugun: osh, manti, lag'mon</p>
    </PageLayout>
  );
}

Ekranda:

text
«Bahor» oshxonasi
Bugun: osh, manti, lag'mon
07:00–23:00, har kuni

Bunday "teshik" — slot deyiladi: komponent joyni belgilaydi, nima qo'yilishini chaqiruvchi hal qiladi. children — asosiy slot, header va footer — nomli slot'lar. Web Components dagi <slot name="header"> ham aynan shu g'oya. React'da u oddiy props.

Diagrammada ko'ring: ma'lumot qaysi yo'l bilan qaysi teshikka tushadi.

flowchart LR
  A["App"] -- "header=" --> H["header slot"]
  A -- "teglar orasi" --> M["children slot"]
  A -- "footer=" --> F["footer slot"]
  subgraph PageLayout
    H
    M
    F
  end

App uchta bo'lakni beradi, PageLayout esa ularning joyini va o'ramini biladi. Sahifa sxemasi bir joyda — butun saytda bir xil.

Tekshirib ko'ring: PageLayout ni footer siz chaqirsak nima bo'ladi?

Javob

footer — undefined, {footer} hech narsa chizmaydi. Lekin bo'sh <footer></footer> elementi DOM'da qoladi. Uni ham olib tashlash kerak bo'lsa — shart bilan: {footer && <footer>{footer}</footer>}. Shartli chizish — keyingi dars.

4. Wrapper komponentlar

"O'ram" (wrapper) — o'zi hech narsa qo'shmaydigan, faqat ichidagisini bezaydigan yoki tartiblaydigan komponent. Ular kichik, lekin butun sayt bo'ylab qayta ishlatiladi:

jsx
function Highlight({ children }) {
  return <mark className="ajratma">{children}</mark>;
}

function PriceRow({ children }) {
  return <p className="narx-qatori">{children}</p>;
}

function App() {
  return (
    <section>
      <PriceRow>
        Osh: <Highlight>35000</Highlight> so'm
      </PriceRow>
      <PriceRow>
        Manti: 30000 so'm <Highlight>Yangi!</Highlight>
      </PriceRow>
    </section>
  );
}

Ekranda:

text
Osh: 35000 so'm
Manti: 30000 so'm Yangi!

Wrapper'ning foydasi: dizayner "ajratilgan narxlar endi sariq emas, yashil bo'lsin" desa, faqat Highlight o'zgaradi. U ishlatilgan 40 joyga tegilmaydi.

Ichma-ich ham bo'ladi: <Card><PriceRow><Highlight>…</Highlight></PriceRow></Card>. Har komponent faqat o'z qatlamini biladi — matryoshka kabi.

5. Kompozitsiya va merosxo'rlik

5.1 Klasslarda meros bor edi

Meros: extends va super darsida klass boshqa klassdan meros olardi. Shunday fikr kelishi tabiiy: "WarningCard extends Card" — ogohlantirish kartasi oddiy kartaning maxsus turi.

React komponentlari esa — funksiyalar, va ular meros olmaydi. Maxsus variant ichiga qo'yish bilan yasaladi:

jsx
function Card({ title, children }) {
  return (
    <section className="card">
      <h2>{title}</h2>
      {children}
    </section>
  );
}

function WarningCard({ children }) {
  return (
    <Card title="Diqqat!">
      <div className="ogohlantirish">{children}</div>
    </Card>
  );
}

function App() {
  return (
    <WarningCard>
      <p>Bugun 22:00 da yopilamiz.</p>
    </WarningCard>
  );
}

Ekranda:

text
Diqqat!
Bugun 22:00 da yopilamiz.

WarningCard — Card ning "maxsus turi". Lekin u Card dan meros olmadi: shunchaki uni o'z ichida ma'lum props bilan chizdi. Bu kompozitsiya (composition) — kichik bo'laklarni bir-birining ichiga qo'yib, kattasini yig'ish.

5.2 Nega kompozitsiya yutadi

Meros (extends) Kompozitsiya
Aloqa qattiq: bola otaning ichini biladi yumshoq: faqat props orqali
O'zgartirish ota o'zgarsa — hamma bolalar xavf ostida har bo'lak alohida
Aralashtirish bitta ota istalgan bo'laklar birikmasi
Tekshirish ierarxiyani bilish kerak props'ga qarash yetadi

React jamoasining eski rasmiy hujjatida shunday yozilgan: Facebook'da (hozirgi Meta) minglab komponent bor, lekin merosxo'rlik ierarxiyasi kerak bo'lgan birorta holat topilmagan. Bu Asosiy tamoyillar: kompozitsiya darsidagi "kompozitsiya — merosdan afzal" qoidasining React'dagi ko'rinishi.

Maslahat: Eski kodda React.Children.map, cloneElement kabi children ni o'zgartiruvchi API'larni uchratasiz. Ular hali bor, lekin hujjatda "kam ishlatiladigan" deb belgilangan. Yangi kodda props va slot'lar yetadi (HOC va render props darsida eski naqshlarni o'qiymiz).

6. children va oraliq komponentlar

Kompozitsiyaning yana bir foydasi bor. Oraliq komponent ma'lumotga tegmasdan uni o'tkazib yuboradi:

jsx
function Sidebar({ children }) {
  return <aside className="yon-panel">{children}</aside>;
}

function UserBadge({ name }) {
  return <p>Ofitsiant: {name}</p>;
}

function App() {
  const waiter = "Sardor";
  return (
    <Sidebar>
      <UserBadge name={waiter} />
    </Sidebar>
  );
}

Ekranda:

text
Ofitsiant: Sardor

Sidebar waiter haqida hech narsa bilmaydi — unga name prop'i ham kerak emas. UserBadge ni App o'zi yasadi va tayyor holda Sidebar ichiga qo'ydi. Agar Sidebar ichida UserBadge yozilganda edi, name ni App → Sidebar → UserBadge deb ikki pog'ona tashish kerak bo'lardi. Ko'p pog'onali tashish (props drilling) muammosini Context I darsida batafsil ko'ramiz — ko'pincha birinchi yechim aynan children.

7. children ga tur yozamiz

TypeScript'da children ning turi — ReactNode, JSX II dagi "{} ga qo'yish mumkin bo'lgan hamma narsa":

tsx
import type { ReactNode } from "react";

type CardProps = {
  title: string;
  children: ReactNode;
};

function Card({ title, children }: CardProps) {
  return (
    <section>
      <h2>{title}</h2>
      {children}
    </section>
  );
}

export default function App() {
  return (
    <Card title="Manti">
      <p>30000 so'm</p>
    </Card>
  );
}

Ekranda:

text
Manti
30000 so'm

import type — faqat tur import qilinadi, build'dan keyin bu qator yo'qoladi (Modullar TypeScript'da dagidek). Endi ikki xato kompilyatsiyada ushlanadi:

tsx
import type { ReactNode } from "react";

type CardProps = {
  title: string;
  children: ReactNode;
};

function Card({ title, children }: CardProps) {
  return (
    <section>
      <h2>{title}</h2>
      {children}
    </section>
  );
}

export function App() {
  return (
    <div>
      <Card title="Osh" />
      <Card title="Manti">{{ narx: 30000 }}</Card>
    </div>
  );
}

Xato:

text
TS2741: Property 'children' is missing in type '{ title: string; }' but required in type 'CardProps'.
TS2353: Object literal may only specify known properties, and 'narx' does not exist in type 'Iterable<ReactNode> | Promise<AwaitedReactNode> | ReactElement<unknown, string | JSXElementConstructor<any>> | ReactPortal'.

Birinchisi — "children majburiy, lekin berilmagan". Bo'sh karta ma'nosiz bo'lsa, children majburiy qolsin. Bo'sh bo'lishi mumkin bo'lsa — children?: ReactNode. Ikkinchisi — obyekt ReactNode emas (JSX II dagi Objects are not valid as a React child endi kompilyatsiyada). Xabardagi uzun ro'yxat — ReactNode ning ichidagi turlar, uni yod olish shart emas.

Teskari holat ham bor. children turida yo'q bo'lsa-yu, uni bersangiz:

tsx
type CardProps = { title: string };

function Card({ title }: CardProps) {
  return <h2>{title}</h2>;
}

export function App() {
  return (
    <Card title="Osh">
      <p>35000 so'm</p>
    </Card>
  );
}

Xato:

text
TS2322: Type '{ title: string; children: Element; }' is not assignable to type 'IntrinsicAttributes & CardProps'.
  Property 'children' does not exist on type 'IntrinsicAttributes & CardProps'.

"children xususiyati CardProps da yo'q." «{children} unutilsa» bo'limidagi jim xato — TypeScript'da jim emas. Komponent children ni qabul qilmasa, uni berish kompilyatsiya xatosi.

8. Vazifalar qadami: Qator va TahrirQatori

8.1 Qator — qatorning qobig'i

v6 da ikkala qator funksiyasi bir xil boshlanardi:

ts
const li = document.createElement("li");
li.dataset.id = String(vazifa.id);
// faqat oddiy qatorda:
li.classList.toggle("bajarildi", vazifa.bajarildi);

Bu — qobiq. Ichi esa har xil: oddiy qatorda katak, yorliq va ikki tugma; tahrirda maydon va boshqa ikki tugma. Qobiqni children li komponentga chiqaramiz — src/Qator.tsx:

tsx
// Qator.tsx — ro'yxat qatorining "qobig'i" (17/#07: children).
// Oddiy qator ham, tahrir qatori ham <li> ichida turadi; ichiga nima
// qo'yilishi — chaqiruvchining ishi (kompozitsiya)
import type { ReactNode } from "react";

type Props = {
  id: number;
  bajarildi?: boolean;
  children: ReactNode;
};

export function Qator({ id, bajarildi = false, children }: Props) {
  return (
    // data-id — vanilla kod (fokus, qo'shni qator) shunga qaraydi
    <li data-id={id} className={bajarildi ? "bajarildi" : undefined}>
      {children}
    </li>
  );
}

Uch narsaga e'tibor bering:

  • data-id={id} — son. v6 da String(vazifa.id) bilan aniq satrga aylantirardik, chunki dataset faqat satr qabul qiladi. JSX'da React atribut qiymatini o'zi satrga aylantiradi.
  • className={bajarildi ? "bajarildi" : undefined} — classList.toggle ning o'rnida. undefined bo'lsa, class atributi umuman yozilmaydi. bajarildi ixtiyoriy va default false: tahrir qatori uni bermaydi.
  • children: ReactNode — majburiy: bo'sh qator bo'lmaydi.

8.2 TahrirQatori — birinchi kompozitsiya

Endi tahrirQatori() ning o'rnini src/TahrirQatori.tsx egallaydi. U ikkita oldingi komponentni yig'adi — Qator (qobiq) va AmalTugmasi (Props darsida yozganimiz):

tsx
// TahrirQatori.tsx — tahrir paytidagi qator: maydon va ikki tugma
import { AmalTugmasi } from "./AmalTugmasi.tsx";
import { Qator } from "./Qator.tsx";
import { Vazifa } from "./vazifa.ts";
import type { VazifaMalumoti } from "./turlar.ts";

// tahrirMaydoni() (render.tsx) shu id bilan topadi
export const TAHRIR_MAYDONI_ID = "tahrir-maydon";

type Props = {
  vazifa: VazifaMalumoti;
};

export function TahrirQatori({ vazifa }: Props) {
  return (
    <Qator id={vazifa.id}>
      {/* 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}
        maxLength={Vazifa.MAKS_UZUNLIK}
        aria-label="Vazifa matni"
      />
      <AmalTugmasi amal="saqla" matn="Saqlash" nomi={vazifa.matn} />
      <AmalTugmasi
        amal="bekor"
        matn="Bekor qilish"
        nomi={vazifa.matn}
      />
    </Qator>
  );
}

Qatorma-qator:

  • <Qator id={vazifa.id}>…</Qator> — maydon va ikki tugma Qator ning children i bo'lib ketdi. bajarildi berilmagan — tahrir qatorida klass yo'q, v6 dagidek.
  • vazifa: VazifaMalumoti — butun vazifa bitta prop bo'lib keladi. VazifaMalumoti — turlar.ts dagi JSON shakli (id, matn, bajarildi, hammasi readonly). Props faqat o'qiladi — tur ham shuni aytadi.
  • defaultValue — value emas. defaultValue maydonga faqat birinchi qiymatni beradi, keyin maydon foydalanuvchiniki. Bu "uncontrolled" maydon — Formalar II darsida chuqur. Izohdagi gap muhim. Tahrir paytida boshqa tabdan o'zgarish kelsa, ro'yxat qayta chiziladi. Lekin React o'sha <input> ni qayta yaratmaydi — yozilayotgan matn joyida qoladi. v6 da buning uchun "qoralamani qo'lda tiklash" kodi bor edi.
  • TAHRIR_MAYDONI_ID — maydonning id'si eksport qilinadi: vanilla kod (render.ts dagi tahrirMaydoni()) maydonni shu bilan topadi va fokus beradi. Izohda render.tsx deyilgani — fayl Ro'yxatlar va key darsida shu nomga o'tadi (ichida JSX paydo bo'ladi). Komponent faylidan konstanta eksport qilish — Komponentlar darsidagi only-export-components holati. Bu vazifalar da Fast Refresh uchun ozgina narx; Hodisalarni boshqarish darsida bu eksport keraksiz bo'ladi.
  • maxLength={Vazifa.MAKS_UZUNLIK} — 100 belgi, vazifa.ts dagi o'sha qoida. HTML'dagi maxlength JSX'da camelCase (JSX I).

npm run tip jim tugaydi. Ekranda hali hech narsa o'zgarmadi: komponentlar tayyor, lekin ularni hali hech kim chizmaydi. Keyingi darsda oddiy qatorni yozamiz. U yerda tahrir yoki oddiy ko'rinishni tanlaydigan VazifaQatori ham yig'iladi.

9. Ko'p uchraydigan xatolar

Belgi Sabab Davosi
ichidagi mazmun ko'rinmaydi {children} qaytarilgan JSX'da yo'q {children} ni joyiga qo'ying
TS2322 … 'children' does not exist props turida children yo'q children: ReactNode qo'shing
TS2741 … 'children' is missing majburiy children berilmagan mazmun bering yoki children?:
Objects are not valid as a React child children ga obyekt berilgan maydonlarini chiqaring
bo'sh <footer> qoladi slot berilmagan, o'ram qolgan {footer && <footer>…}
extends Card bilan "maxsus karta" klass merosi odati ichiga qo'ying (kompozitsiya)

10. Mashqlar

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

1-mashq (oson): nima chiqadi?

Ishga tushirmasdan oldin ekranni yozing.

jsx
function Box({ title, children }) {
  return (
    <div>
      <h3>{title}</h3>
      <p>[{children}]</p>
    </div>
  );
}

function Empty({ children }) {
  return <p>Bo'sh quti</p>;
}

function App() {
  return (
    <div>
      <Box title="A">Osh</Box>
      <Box title="B" />
      <Empty>Manti</Empty>
    </div>
  );
}
  • B sarlavhasi ostidagi qator: ]
  • Empty ichidagi "Manti" ekranda bormi (ha/yo'q):
Yechim

Ekranda:

text
A
[Osh]
B
[]
Bo'sh quti

B — children yo'q (undefined), qavslar orasi bo'sh. Empty children ni oladi, lekin hech qayerga qo'ymaydi — "Manti" yo'qoladi va xato chiqmaydi.

2-mashq (o'rta): kartalar sahifasi

Card komponentini yozing: props — title, children va ixtiyoriy footer. footer berilsa, u <small> ichida kartaning pastida chiqsin. Berilmasa, <small> umuman bo'lmasin. Shart uchun {footer && …} yetadi: footer — satr, element yoki undefined, son emas, shuning uchun 0 tuzog'i yo'q. App uchta karta chizsin:

text
Osh
Choyxona oshi
35000 so'm
Manti
4 dona
30000 so'm
Aloqa
+998 90 000 00 00

Birinchi ikkita kartada narx — footer, uchinchisida footer yo'q.

Yechim
jsx
function Card({ title, footer, children }) {
  return (
    <section className="card">
      <h2>{title}</h2>
      {children}
      {footer && <small>{footer}</small>}
    </section>
  );
}

function App() {
  return (
    <div>
      <Card title="Osh" footer="35000 so'm">
        <p>Choyxona oshi</p>
      </Card>
      <Card title="Manti" footer={<b>30000 so'm</b>}>
        <p>4 dona</p>
      </Card>
      <Card title="Aloqa">
        <p>+998 90 000 00 00</p>
      </Card>
    </div>
  );
}

Ekranda:

text
Osh
Choyxona oshi
35000 so'm
Manti
4 dona
30000 so'm
Aloqa
+998 90 000 00 00

Bu yerda <small> — inline element. U yangi qatorda chiqdi, chunki undan oldingi <p> — blok element. Slot'ga satr ham ("35000 so'm"), element ham (<b>…</b>) berish mumkin — ikkalasi ham ReactNode.

3-mashq (qiyin): chek (TypeScript)

«Bahor» kassasi uchun chek yasang, .tsx da. Ikki komponent:

  • Receipt — props: title: string, children: ReactNode, total: ReactNode (slot). Chizadi: <h2> da sarlavha, keyin <ul> ichida children, oxirida <p> da Jami: va total.
  • ReceiptLine — props: name: string, price: number, count?: number (default 1). Chizadi: <li> — Osh × 2: 70000.

App chek chizsin: osh × 2, ko'k choy × 3, non (3000). total slotiga jami summani <b> ichida bering — uni App hisoblasin (70000 + 15000 + 3000). Ekranda:

text
Chek №17
Osh × 2: 70000
Ko'k choy × 3: 15000
Non × 1: 3000
Jami: 88000 so'm

Ishora: «Bir nechta "slot"» va «children ga tur yozamiz» bo'limlari.

Yechim
tsx
import type { ReactNode } from "react";

type ReceiptProps = {
  title: string;
  children: ReactNode;
  total: ReactNode;
};

function Receipt({ title, children, total }: ReceiptProps) {
  return (
    <section>
      <h2>{title}</h2>
      <ul>{children}</ul>
      <p>Jami: {total}</p>
    </section>
  );
}

type ReceiptLineProps = {
  name: string;
  price: number;
  count?: number;
};

function ReceiptLine({ name, price, count = 1 }: ReceiptLineProps) {
  return (
    <li>
      {name} × {count}: {price * count}
    </li>
  );
}

export default function App() {
  const total = 35000 * 2 + 5000 * 3 + 3000;
  return (
    <Receipt title="Chek №17" total={<b>{total} so'm</b>}>
      <ReceiptLine name="Osh" price={35000} count={2} />
      <ReceiptLine name="Ko'k choy" price={5000} count={3} />
      <ReceiptLine name="Non" price={3000} />
    </Receipt>
  );
}

Ekranda:

text
Chek №17
Osh × 2: 70000
Ko'k choy × 3: 15000
Non × 1: 3000
Jami: 88000 so'm

Receipt qatorlar haqida hech narsa bilmaydi — u faqat chek shaklini beradi. ReceiptLine esa chek haqida bilmaydi — u bitta qator. Ularni App yig'di: bu kompozitsiya. Jami summa hozircha qo'lda hisoblangan. Ro'yxat massivdan chizilganda uni reduce bilan hisoblash mumkin bo'ladi (Ro'yxatlar va key).

4-mashq: Vazifalar qadami

refactor/royxat-react branch'ida src/Qator.tsx va src/TahrirQatori.tsx ni «Vazifalar qadami» bo'limidagidek yozing. npm run tip toza bo'lsin. Savol: TahrirQatori da nega <Qator> ga bajarildi berilmagan, OddiyQator da esa beriladi (keyingi darsda ko'rasiz)?

Yechim

v6 dagi tahrirQatori() ham bajarildi klassini qo'ymasdi — tahrir paytida qator chizilmagan (ustidan chiziq yo'q) ko'rinadi. Qator da bajarildi ixtiyoriy va default false, shuning uchun TahrirQatori uni yozmaydi. Oddiy qator esa vazifa holatiga qarab chiziladi va bajarildi={vazifa.bajarildi} beradi. Bitta qobiq — ikki xil ishlatish: slot'ga har xil mazmun, props'ga har xil qiymat.

11. Real ishda

  • Layout komponentlari — har loyihada: PageLayout, Sidebar, Modal, Card. Ular children va nomli slot'lar bilan yoziladi.
  • UI kutubxonalari (shadcn/ui, Radix, MUI) — kompozitsiya ustiga qurilgan: <Dialog><DialogTitle>…</DialogTitle></Dialog>. Bunday "bir-biriga bog'langan komponentlar" naqshi — Compound komponentlar va slot naqshi darsida.
  • Optimallashtirish: children orqali berilgan JSX ota qayta chizilganda ham qayta yasalmaydi — bu bepul tezlashtirish usuli (Kompozitsiya orqali optimallashtirish).
  • Intervyu savollari: "children nima?", "React'da merosxo'rlik ishlatiladimi?", "Komponentga bir nechta JSX bo'lagini qanday berasiz?".

Xulosa

  • Teglar orasidagi hamma narsa komponentga children prop'i bo'lib keladi; uni {children} bilan kerakli joyga qo'yasiz.
  • {children} unutilsa — mazmun jim yo'qoladi; TypeScript turida children bo'lmasa, uni berish — xato.
  • Qisqa qiymat — props, katta JSX bo'lagi — children; bir nechta joy — JSX'ni nomli props (slot) bilan bering.
  • Maxsus variant meros bilan emas, ichiga qo'yish bilan yasaladi — bu kompozitsiya.
  • children turi — ReactNode.
  • vazifalar da Qator — umumiy <li> qobig'i, TahrirQatori — Qator va AmalTugmasi dan yig'ilgan birinchi kompozitsiya.

Keyingi dars: Shartli render — if, ternary va && bilan qaysi UI chizilishini tanlaymiz va vazifalar da tahrir yoki oddiy qatorni tanlaydigan VazifaQatori ni yozamiz.

Manbalar

  • React: "Passing Props to a Component" — "Passing JSX as children" — react.dev/learn/passing-props-to-a-component
  • React: Children va cloneElement — "Legacy React APIs" — react.dev/reference/react/legacy
  • React (eski hujjat): "Composition vs Inheritance" — legacy.reactjs.org/docs/composition-vs-inheritance.html
Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
children va kompozitsiya: React komponentlarini lego kabi yig'ish — slot, wrapper va Card naqshi — IlmHamroh