IlmHamroh
JavaScript Full-stack/17-qism. React asoslari8/45-dars21 daqiqa
Mundarija (28)

Shartli render: React'da if, ternary, && va null — yuklanish, xato va bo'sh holatlar

Qisqacha: React'da "qaysi UI chizilsin" degan savolga oddiy JavaScript javob beradi. Komponent boshida if + return — butunlay boshqa ko'rinish uchun. JSX ichida ternary (a ? <X/> : <Y/>) — ikki variantdan biri uchun. && — "bor yoki yo'q" uchun, lekin chap tomoni haqiqiy boolean bo'lsin (count > 0 &&, aks holda 0 ko'rinadi). null qaytarish — "hech narsa chizma". Haqiqiy ilovada bitta ma'lumot to'rt holatda bo'ladi: yuklanmoqda, xato, bo'sh va tayyor — har biri o'z ekrani bilan.

Bu darsda

  • if va erta return bilan komponentning butun ko'rinishini tanlaysiz.
  • JSX ichida ternary va && ni to'g'ri ishlatasiz, 0 && tuzog'idan qochasiz.
  • Komponentni null bilan yashirasiz va bu qaror kimniki ekanini tushunasiz.
  • Murakkab shartni JSX'dan oldin o'zgaruvchiga chiqarasiz.
  • Yuklanish, xato, bo'sh va tayyor holatlarini to'liq chizasiz — TypeScript'da birorta ham unutilmaydigan qilib.

Oldin bilishingiz kerak: JSX II: ifodalar, Fragment va nima ekranga chiqadi, children va kompozitsiya, return va erta qaytish.

1. Nega bu kerak?

«Bahor» saytidagi buyurtma sahifasi. Mijoz "Buyurtmalarim" ni ochdi. Ma'lumot serverdan keladi — bir soniya kutish bor. Internet uzilib qolishi mumkin. Mijoz hali hech narsa buyurtma qilmagan bo'lishi ham mumkin. Va nihoyat, ro'yxat keldi.

Bitta joy — to'rt xil ekran: "Yuklanmoqda…", "Xato: internetni tekshiring", "Hali buyurtma yo'q" va ro'yxatning o'zi. Birini unutsangiz, mijoz bo'sh oq sahifaga qarab qoladi va "sayt buzilgan" deb o'ylaydi.

Vanilla'da bu if lar bilan yechilardi: vazifalar dagi qatorYasa() vazifa tahrirdami yoki yo'qmi, shunga qarab ikki funksiyadan birini chaqirardi. React'da ham xuddi shu if. JSX — JavaScript, shuning uchun alohida "shart sintaksisi" o'rganish shart emas. Faqat bitta cheklov bor: JSX I darsida ko'rganimizdek, {} ichida if yozib bo'lmaydi. Bugun shu cheklov atrofidagi to'rt usulni o'rganamiz.

2. if va erta return

2.1 Butunlay boshqa ko'rinish

Shartga qarab komponent butunlay boshqa JSX qaytarsa — oddiy if:

jsx
function WorkStatus({ hour }) {
  if (hour < 7 || hour >= 23) {
    return <p>Yopiq. Ertalab 07:00 da ochilamiz.</p>;
  }
  return (
    <div>
      <p>Ochiq!</p>
      <p>Yopilishga {23 - hour} soat qoldi.</p>
    </div>
  );
}

function App() {
  return (
    <>
      <WorkStatus hour={6} />
      <WorkStatus hour={20} />
    </>
  );
}

Ekranda:

text
Yopiq. Ertalab 07:00 da ochilamiz.
Ochiq!
Yopilishga 3 soat qoldi.

if JSX'dan tashqarida — komponent funksiyasining oddiy qismida. Bu yerda JavaScript'ning hamma imkoniyati bor: if, else, switch, sikl. Erta return (erta qaytish) — "maxsus holatni birinchi hal qil, asosiy ko'rinish pastda qolsin". Funksiya qisqa va o'qilishi oson bo'ladi.

2.2 null — "hech narsa chizma"

Komponent o'zini butunlay yashirishi mumkin:

jsx
function SaleBanner({ isActive }) {
  if (!isActive) {
    return null;
  }
  return <p>Aksiya: har juma ko'k choy bepul!</p>;
}

function App() {
  return (
    <>
      <h1>«Bahor»</h1>
      <SaleBanner isActive={false} />
      <p>Menyu pastda</p>
    </>
  );
}

Ekranda:

text
«Bahor»
Menyu pastda

null — DOM'ga hech narsa qo'shmaydi. Lekin komponent baribir chaqirildi: React SaleBanner ni ishga tushirdi, u esa "hech narsa" deb javob berdi.

Savol: yashirish qarori kimniki — bolaniki yoki otaniki? Ikki yo'l bor:

Bola o'zi yashiradi Ota umuman chizmaydi
Kod if (!isActive) return null; {isActive && <SaleBanner />}
Qachon qaror bolaning ma'lumotiga bog'liq qaror otaning ma'lumotiga bog'liq
Komponent chaqiriladimi ha yo'q

Odatda ikkinchisi tushunarliroq: otaning JSX'iga qarab, nima chizilishi darhol ko'rinadi.

Tekshirib ko'ring: if (!isActive) return; (qiymatsiz return) yozsak nima bo'ladi?

Javob

Ekran bir xil. Qiymatsiz return — undefined, React 19 esa uni null kabi "hech narsa" deb qabul qiladi (Komponentlar darsida return unutilgan holatda ko'rgandik). Lekin return null; aniqroq: "bu yerda ataylab hech narsa yo'q" deydi. TypeScript va linterlar ham shu shaklni kutadi.

3. JSX ichida: ternary va &&

3.1 Ternary — ikkidan biri

Ko'rinishning kichik bir qismi shartga bog'liq bo'lsa, butun komponentni ikki marta yozish ortiqcha. Ternary (if / else va shartli operator) — ifoda, demak {} ichiga sig'adi:

jsx
function MenuCard({ name, price, soldOut }) {
  return (
    <li className={soldOut ? "tugagan" : undefined}>
      {name} — {soldOut ? <s>{price} so'm</s> : <b>{price} so'm</b>}
      {soldOut ? " (tugadi)" : ""}
    </li>
  );
}

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

Ekranda:

text
Osh — 35000 so'm
Somsa — 8000 so'm (tugadi)

Ternary uch joyda ishladi: atributda (className), element tanlashda (<s> yoki <b>) va matnda. Atributdagi undefined — "atributni umuman qo'yma" (Props mashqida ko'rgandik).

3.2 && — bor yoki yo'q

"Else" qismi kerak bo'lmasa — &&. Mantiqiy operatorlar dan eslang: a && b — a rost bo'lsa b ni qaytaradi, aks holda a ning o'zini:

jsx
function CartBadge({ count, isVip }) {
  return (
    <p>
      Savat
      {isVip && " ⭐"}
      {count > 0 && <b> ({count})</b>}
    </p>
  );
}

function App() {
  return (
    <>
      <CartBadge count={3} isVip />
      <CartBadge count={0} isVip={false} />
    </>
  );
}

Ekranda:

text
Savat ⭐ (3)
Savat

3.3 0 && — qisqa takror

Ikkinchi qatorda count > 0 yozilganiga e'tibor bering. JSX II darsida batafsil ko'rgan tuzog'imiz: {count && <b>…</b>} bo'sh savatda 0 ni chizadi. 0 && … → 0, son esa React'da ko'rinadi (false dan farqli). Qoida qisqa:

  • && chapida son bo'lsa — count > 0 && (yoki ternary);
  • && chapida boolean bo'lsa (isVip) — xavf yo'q;
  • .length && — o'sha son: items.length > 0 &&.

Batafsil misollar, NaN holati va TypeScript nega ushlamasligi — JSX II darsida.

3.4 Ternary yoki &&?

Vaziyat Usul Misol
ikki variant ternary {isOpen ? "Ochiq" : "Yopiq"}
bor yoki yo'q && (chapi boolean) {isVip && <Star />}
son bo'yicha bor/yo'q taqqoslash + && {count > 0 && <Badge />}
atribut bor yoki yo'q ternary + undefined className={x ? "a" : undefined}
butunlay boshqa ko'rinish if + return «if va erta return» bo'limi

Tekshirib ko'ring: {name && <p>Salom, {name}!</p>} — name bo'sh satr "" bo'lsa, ekranda nima chiqadi? 0 && dagidek tuzoq bormi?

Javob

Hech narsa chiqmaydi va tuzoq yo'q. "" && … → "", bo'sh satr esa ekranda hech narsa chizmaydi (JSX II jadvali). Tuzoq faqat sonlarda (0, NaN): ular ko'rinadi. Shunga qaramay, name !== "" && yozish niyatni aniqroq ko'rsatadi.

4. JSX'ni o'zgaruvchiga saqlash

Shart murakkablashsa, JSX ichidagi ternary'lar bir-birining ichiga kirib ketadi. "Ternary ichida ternary" — o'qib bo'lmaydigan kod. Yechim: JSX ham qiymat (JSX II), demak uni oldindan o'zgaruvchiga hisoblab qo'yish mumkin:

jsx
function DeliveryInfo({ distanceKm }) {
  let message;
  if (distanceKm <= 3) {
    message = <b>Bepul yetkazamiz</b>;
  } else if (distanceKm <= 10) {
    message = <span>Yetkazish: {distanceKm * 2000} so'm</span>;
  } else {
    message = <span>Bu manzilga yetkazmaymiz</span>;
  }

  return <p>{distanceKm} km: {message}</p>;
}

function App() {
  return (
    <>
      <DeliveryInfo distanceKm={2} />
      <DeliveryInfo distanceKm={5} />
      <DeliveryInfo distanceKm={15} />
    </>
  );
}

Ekranda:

text
2 km: Bepul yetkazamiz
5 km: Yetkazish: 10000 so'm
15 km: Bu manzilga yetkazmaymiz

Uch shoxli shart return dan oldin, oddiy if/else da. return esa faqat sxema: "masofa va xabar". Ichma-ich ternary bilan yozilganini o'qish ancha qiyin bo'lardi:

jsx
// ❌ o'qish qiyin
<p>{distanceKm} km: {distanceKm <= 3 ? <b>…</b> : distanceKm <= 10
  ? <span>…</span> : <span>…</span>}</p>

5. To'rt holat: yuklanmoqda, xato, bo'sh, tayyor

5.1 Jonli misol

Endi «Nega bu kerak?» bo'limidagi "Buyurtmalarim" sahifasi. Ma'lumot serverdan kelishini hozircha tugmalar bilan taqlid qilamiz. Haqiqiy so'rov — useEffect va Effektda ma'lumot olish darslarida. Har tugma status va orders ni o'zgartirib, draw() ni chaqiradi (vanilla usul, JSX II dagidek). Blok tugmalarni ketma-ket o'zi bosadi:

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

const root = createRoot(document.getElementById("root"));
let status = "loading";
let orders = [];

function OrderList({ status, orders }) {
  if (status === "loading") {
    return <p>Yuklanmoqda…</p>;
  }
  if (status === "error") {
    return <p role="alert">Xato: internet aloqasini tekshiring.</p>;
  }
  if (orders.length === 0) {
    return <p>Hali buyurtma yo'q. Menyuga o'ting!</p>;
  }
  return (
    <ul>
      {orders.map((o) => (
        <li key={o.id}>{o.dish} × {o.count}</li>
      ))}
    </ul>
  );
}

function set(newStatus, newOrders) {
  status = newStatus;
  orders = newOrders;
  draw();
}

function draw() {
  console.log("holat:", status, orders.length);
  root.render(
    <div>
      <OrderList status={status} orders={orders} />
      <button onClick={() => set("error", [])}>Xato</button>
      <button onClick={() => set("ready", [])}>Bo'sh</button>
      <button onClick={() => set("ready", [
        { id: 1, dish: "Osh", count: 2 },
        { id: 2, dish: "Ko'k choy", count: 1 },
      ])}>Keldi</button>
    </div>
  );
}
draw();

Konsolda:

text
holat: loading 0
holat: error 0
holat: ready 0
holat: ready 2

Ekranda:

text
Osh × 2
Ko'k choy × 1
XatoBo'shKeldi

«Ishga tushir» ni bosib, tugmalarni o'zingiz sinang. Har bosishda nima bo'lishi:

Qadam State Ekranda
boshida status: "loading" Yuklanmoqda…
«Xato» status: "error" Xato: internet aloqasini tekshiring.
«Bo'sh» status: "ready", orders: [] Hali buyurtma yo'q. Menyuga o'ting!
«Keldi» status: "ready", 2 ta buyurtma Osh × 2 · Ko'k choy × 1

Erta return lar zanjiri — qaror daraxti. Diagrammada yuqoridan pastga o'qing: har savolda bitta shox tanlanadi.

flowchart TD
  S{"status?"} -- "loading" --> L["Yuklanmoqda…"]
  S -- "error" --> E["Xato xabari"]
  S -- "ready" --> B{"orders bo'shmi?"}
  B -- "ha" --> Y["Hali buyurtma yo'q"]
  B -- "yo'q" --> R["Buyurtmalar ro'yxati"]

Tartib muhim. Avval loading va error tekshiriladi: ular paytida orders hali haqiqiy emas. Keyin — bo'sh holat, eng oxirida — asosiy ko'rinish. Bu tartib erta return lar bilan o'z-o'zidan saqlanadi. Xato paragrafidagi role="alert" — Malika'ning ekran o'quvchisi xabarni darhol o'qib beradi (Dinamik UI'da qulaylik).

5.2 TypeScript bilan: birorta holat unutilmasin

Satrli status da xato oson: "loadng" deb yozsangiz — jim. Bunday holatlar uchun discriminated union bor. Har holat — o'z maydonlari bilan:

tsx
type Order = { id: number; dish: string; count: number };

type OrdersState =
  | { kind: "loading" }
  | { kind: "error"; message: string }
  | { kind: "ready"; orders: Order[] };

function OrderList({ state }: { state: OrdersState }) {
  switch (state.kind) {
    case "loading":
      return <p>Yuklanmoqda…</p>;
    case "error":
      return <p role="alert">Xato: {state.message}</p>;
    case "ready":
      if (state.orders.length === 0) {
        return <p>Hali buyurtma yo'q.</p>;
      }
      return (
        <ul>
          {state.orders.map((o) => (
            <li key={o.id}>{o.dish} × {o.count}</li>
          ))}
        </ul>
      );
    default: {
      const unhandled: never = state;
      return unhandled;
    }
  }
}

export default function App() {
  return (
    <>
      <OrderList
        state={{ kind: "error", message: "server javob bermadi" }}
      />
      <OrderList state={{ kind: "ready", orders: [] }} />
    </>
  );
}

Ekranda:

text
Xato: server javob bermadi
Hali buyurtma yo'q.

Ikki foyda bor. Birinchisi: state.message faqat "error" holatida bor — "loading" da uni o'qishga urinsangiz, tsc to'xtatadi. Ikkinchisi: default dagi never (to'liqlik tekshiruvi). Ertaga kimdir { kind: "empty" } qo'shib, switch ga yozishni unutsa — kompilyator xato beradi. vazifalar da shu naqsh bor: QoshishNatijasi turi va uning switch i (State I darsida ko'ramiz).

6. Shartli atributlar

Shart faqat elementni emas, atributni ham boshqaradi. Uch holat bilan tanishamiz:

jsx
function SubmitButton({ isSaving, hasError }) {
  return (
    <button
      type="submit"
      disabled={isSaving}
      aria-invalid={hasError ? true : undefined}
    >
      {isSaving ? "Saqlanmoqda…" : "Saqlash"}
    </button>
  );
}

function App() {
  return (
    <form>
      <SubmitButton isSaving={false} hasError={false} />
      <SubmitButton isSaving hasError />
    </form>
  );
}

Ekranda:

text
SaqlashSaqlanmoqda…
  • disabled={isSaving} — boolean atribut: false bo'lsa React uni umuman qo'ymaydi, true bo'lsa — disabled="".
  • aria-invalid={hasError ? true : undefined} — aria-* atributlari esa satr sifatida yoziladi: false bersangiz, DOM'da aria-invalid="false" qoladi. Shuning uchun "yo'q" holatda — undefined.
  • Matn — ternary bilan.

checked — alohida holat. Faqat o'qish uchun chizilgan katak:

jsx
function App() {
  return (
    <label>
      <input type="checkbox" checked />
      Osh tayyor
    </label>
  );
}

Konsolda:

text
You provided a `checked` prop to a form field without an `onChange` handler. This will render a read-only field. If the field should be mutable use `defaultChecked`. Otherwise, set either `onChange` or `readOnly`.

Ekranda:

text
Osh tayyor

"Siz forma maydoniga checked berdingiz, lekin onChange ishlovchisi yo'q. U faqat o'qiladigan maydon bo'lib chiziladi. O'zgarishi kerak bo'lsa — defaultChecked ishlating. Aks holda onChange yoki readOnly qo'ying." React ogohlantirdi: "katak qiymatini sen boshqaryapsan, lekin bosilganda nima bo'lishini aytmading". Hozircha to'g'ri javob — readOnly: "bu katakni ataylab faqat ko'rsataman". Bu vazifalar dagi katakka kerak bo'ladi — «Vazifalar qadami» bo'limida.

7. Vazifalar qadami: BelgilanganMatn, OddiyQator, VazifaQatori

Bugun uchta komponent yoziladi va ro'yxat qatori to'liq bo'ladi. Kanon fayllaridagi uzun izoh qatorlari telefon ekraniga sig'ishi uchun qayta bo'lingan — mazmuni o'sha.

7.1 BelgilanganMatn — mos bo'laklar <mark> ichida

Qidiruv maydoniga "non" yozilsa, "Non olish" dagi mos bo'lak <mark> bilan ajratiladi. v6 dagi belgilanganMatn() <mark> elementlarini createElement bilan yasardi. Endi src/BelgilanganMatn.tsx:

tsx
// BelgilanganMatn.tsx — qidiruvga mos bo'laklar <mark> ichida
// (14/#11). v6 da: document.createElement("mark") + textContent.
// JSX'da {matn} — har doim matn: React uni o'zi ekranlaydi,
// "<b>" HTML bo'lib qolmaydi
import { moslar } from "./qidiruv.ts";

type Props = {
  matn: string;
  sorov: string;
};

export function BelgilanganMatn({ matn, sorov }: Props) {
  const qismlar = [];
  let joy = 0;
  for (const [boshi, oxiri] of moslar(matn, sorov)) {
    qismlar.push(matn.slice(joy, boshi));
    // key: massivdagi element — React ularni tartib bo'yicha
    // tanisin. Bo'lak boshi — shu matn ichida takrorlanmaydi
    qismlar.push(<mark key={boshi}>{matn.slice(boshi, oxiri)}</mark>);
    joy = oxiri;
  }
  qismlar.push(matn.slice(joy));
  // Bo'sh satrlar ekranda ko'rinmaydi — v6 dagidek filtr shart emas
  return <>{qismlar}</>;
}

Bu yerdagi "shart" — for sikli ichida: mos bo'lak bo'lsa — <mark>, bo'lmasa — oddiy matn. moslar() (Matn algoritmlari darsida yozilgan qidiruv.ts dan) har mos bo'lakning [boshi, oxiri] oralig'ini beradi. Sorov bo'sh bo'lsa — bo'sh massiv, sikl bir marta ham aylanmaydi va butun matn bitta satr bo'lib qoladi.

Uch detal:

  • key={boshi} — massivdagi element key so'raydi (JSX II). Bo'lak boshi bitta matn ichida takrorlanmaydi — yaxshi kalit. key ning to'liq qoidalari — keyingi darsda.
  • Bo'sh satrlar (matn.slice(0, 0) → "") massivda qoladi, lekin ekranda hech narsa chizmaydi. v6 dagi .filter((qism) => qism !== "") endi kerak emas.
  • qismlar.push — komponent ichida massivni o'zgartirish. Bu ruxsat etilganmi? Ha: massiv shu chaqiruvda yaratilgan. Nega bu muhim — Pure komponentlar darsida.

Komponentni jonli sinab ko'ramiz. moslar() o'rniga sodda nusxa — katta-kichik harfni farqlamaydigan indexOf:

jsx
// Sodda moslar(): katta-kichik harf farqsiz, apostrof qoidalarisiz
function moslar(matn, sorov) {
  const natija = [];
  if (sorov === "") return natija;
  const kichik = matn.toLowerCase();
  const izla = sorov.toLowerCase();
  let joy = kichik.indexOf(izla);
  while (joy !== -1) {
    natija.push([joy, joy + izla.length]);
    joy = kichik.indexOf(izla, joy + izla.length);
  }
  return natija;
}

function BelgilanganMatn({ matn, sorov }) {
  const qismlar = [];
  let joy = 0;
  for (const [boshi, oxiri] of moslar(matn, sorov)) {
    qismlar.push(matn.slice(joy, boshi));
    qismlar.push(<mark key={boshi}>{matn.slice(boshi, oxiri)}</mark>);
    joy = oxiri;
  }
  qismlar.push(matn.slice(joy));
  return <>{qismlar}</>;
}

function App() {
  return (
    <ul>
      <li><BelgilanganMatn matn="Non olish #bozor" sorov="NON" /></li>
      <li>
        <BelgilanganMatn matn="Osh, osh va yana osh" sorov="osh" />
      </li>
      <li><BelgilanganMatn matn="Choy damlash" sorov="" /></li>
    </ul>
  );
}

Ekranda:

text
Non olish #bozor
Osh, osh va yana osh
Choy damlash

Ekran matnida <mark> ko'rinmaydi — u inline teg, matn o'sha. «Ishga tushir» natija oynasida esa mos bo'laklar sariq fon bilan ajralib turadi.

7.2 OddiyQator — katak, yorliq, ikki tugma

src/OddiyQator.tsx — v6 dagi oddiyQator() o'rnida. U uchta oldingi komponentni yig'adi:

tsx
// OddiyQator.tsx — katak, matn va ikki tugma (17/#06: props)
import { AmalTugmasi } from "./AmalTugmasi.tsx";
import { BelgilanganMatn } from "./BelgilanganMatn.tsx";
import { Qator } from "./Qator.tsx";
import type { VazifaMalumoti } from "./turlar.ts";

type Props = {
  vazifa: VazifaMalumoti;
  sorov: string;
};

export function OddiyQator({ vazifa, sorov }: Props) {
  const katakId = `vazifa-${vazifa.id}`;
  return (
    <Qator id={vazifa.id} bajarildi={vazifa.bajarildi}>
      {/* checked — holatdan (controlled). Bosilishini hozircha
          vanilla ushlaydi (asosiy.ts), React'ga readOnly bilan
          aytamiz: "buni men o'zgartirmayman" — #11 da onChange
          keladi */}
      <input
        type="checkbox"
        id={katakId}
        data-amal="almashtir"
        checked={vazifa.bajarildi}
        readOnly
      />
      <label htmlFor={katakId}>
        <BelgilanganMatn matn={vazifa.matn} sorov={sorov} />
      </label>
      <AmalTugmasi
        amal="tahrirla"
        matn="Tahrirlash"
        nomi={vazifa.matn}
      />
      <AmalTugmasi amal="ochir" matn="O'chirish" nomi={vazifa.matn} />
    </Qator>
  );
}
  • bajarildi={vazifa.bajarildi} — Qator ichidagi shartli className ni boshqaradi (children darsidagi ternary).
  • checked + readOnly — «Shartli atributlar» bo'limidagi ogohlantirishning javobi. Izohdagi controlled (boshqariladigan) — maydon qiymatini brauzer emas, React beradi: katak vazifa.bajarildi nima desa, shuni ko'rsatadi. Bu so'zni Formalar I darsida chuqur o'rganamiz. Katak holati vazifadan olinadi, bosishni esa hozircha vanilla delegatsiya ushlaydi. Hodisalarni boshqarish darsida readOnly o'rniga onChange keladi.
  • katakId — <label htmlFor> va <input id> bog'lanishi: yorliqni bosish ham katakni bosadi. Bu id'ni e2e tekshiruv ham ishlatadi (#vazifa-1).

7.3 VazifaQatori — qaysi ko'rinish?

Va nihoyat, bugungi mavzu toza ko'rinishda — src/VazifaQatori.tsx:

tsx
// VazifaQatori.tsx — qaysi ko'rinish: tahrir yoki oddiy (17/#08)
import { OddiyQator } from "./OddiyQator.tsx";
import { TahrirQatori } from "./TahrirQatori.tsx";
import type { VazifaMalumoti } from "./turlar.ts";

type Props = {
  vazifa: VazifaMalumoti;
  sorov: string;
  tahrirda: boolean;
};

export function VazifaQatori({ vazifa, sorov, tahrirda }: Props) {
  if (tahrirda) {
    return <TahrirQatori vazifa={vazifa} />;
  }
  return <OddiyQator vazifa={vazifa} sorov={sorov} />;
}

v6 dagi qatorYasa() bilan solishtiring — mantiq aynan bir xil:

ts
function qatorYasa(vazifa: Vazifa): HTMLLIElement {
  if (vazifa.id === holat.tahrirId) {
    return tahrirQatori(vazifa);
  }
  return oddiyQator(vazifa);
}

Bitta farq bor: v6 dagi funksiya global holat.tahrirId ga o'zi qarardi. VazifaQatori esa hech narsaga "qaramaydi" — kerakli hamma narsa props bo'lib keladi (tahrirda: boolean). U Pure komponent bo'ladi: bir xil props — doim bir xil qator.

Uchala fayl tayyor, npm run tip jim tugaydi. Qatorlar hali ekranga chiqmaydi — ro'yxatni React'ga berish va commit keyingi darsda.

8. Ko'p uchraydigan xatolar

Belgi Sabab Davosi
ekranda yolg'iz 0 {count && …} count > 0 && (JSX II)
JSX sintaksis xatosi if da {if (…) …} — {} ichida ko'rsatma ternary yoki if ni JSX'dan oldin
bo'sh oq ekran yuklanish yoki xato holati chizilmagan to'rt holatning har biriga ko'rinish
aria-invalid="false" qoladi aria-* ga false berilgan undefined bering
checked … without an onChange faqat ko'rsatiladigan katak readOnly yoki onChange
ternary ichida ternary ko'p shoxli shart JSX ichida o'zgaruvchiga chiqaring

9. Mashqlar

Mashqlar kurs/mashqlar/17/08-shartli-render/ da. Har yechimni «Ishga tushir» bilan sinang.

1-mashq (oson): qaysi qator chiqadi?

jsx
function Info({ guests, note, isOpen }) {
  return (
    <div>
      <p>A: {isOpen ? "ochiq" : "yopiq"}</p>
      <p>B: {guests && `${guests} mehmon`}</p>
      <p>C: {guests > 0 && `${guests} mehmon`}</p>
      <p>D: {note ?? "izoh yo'q"}</p>
    </div>
  );
}

function App() {
  return <Info guests={0} note={null} isOpen={false} />;
}
  • B qatorida, B: dan keyin:
  • D qatorida, D: dan keyin:
Yechim

Ekranda:

text
A: yopiq
B: 0
C:
D: izoh yo'q

B — 0 && … → 0, ko'rinadi. C — 0 > 0 → false, hech narsa. D — ?? faqat null/undefined da o'ng tomonni oladi (?? va ?.).

2-mashq (o'rta): stol band qilish holati

TableStatus komponentini yozing. Props: status — "free", "reserved" yoki "closed", va guestName (faqat reserved da beriladi). Talablar:

  • closed — komponent hech narsa chizmasin (null);
  • free — <p> "Stol bo'sh" va <button> "Band qilish";
  • reserved — <p> "Band: " va mehmon ismi qalin (<b>).

Erta return lar bilan yozing. App to'rtta stol chizsin: 1-stol bo'sh, 2-stol Malika uchun band, 3-stol yopiq, 4-stol bo'sh. Har stol oldida <h3> da raqami.

text
1-stol
Stol bo'sh
Band qilish
2-stol
Band: Malika
3-stol
4-stol
Stol bo'sh
Band qilish
Yechim
jsx
function TableStatus({ status, guestName }) {
  if (status === "closed") {
    return null;
  }
  if (status === "reserved") {
    return (
      <p>
        Band: <b>{guestName}</b>
      </p>
    );
  }
  return (
    <>
      <p>Stol bo'sh</p>
      <button type="button">Band qilish</button>
    </>
  );
}

function App() {
  return (
    <section>
      <h3>1-stol</h3>
      <TableStatus status="free" />
      <h3>2-stol</h3>
      <TableStatus status="reserved" guestName="Malika" />
      <h3>3-stol</h3>
      <TableStatus status="closed" />
      <h3>4-stol</h3>
      <TableStatus status="free" />
    </section>
  );
}

Ekranda:

text
1-stol
Stol bo'sh
Band qilish
2-stol
Band: Malika
3-stol
4-stol
Stol bo'sh
Band qilish

free — oxirgi return, "asosiy" holat. Tugma <p> dan keyin yangi qatorda chiqdi: oldidagi <p> blok element. 3-stolda sarlavha qoldi, komponent esa hech narsa chizmadi. Sarlavhani ham yashirish kerak bo'lsa, shartni otaga ko'chirish kerak — «null — "hech narsa chizma"» bo'limidagi jadval.

3-mashq (qiyin): to'lov holati (TypeScript)

Click/Payme orqali to'lov sahifasi uchun PaymentState turini va PaymentStatus komponentini .tsx da yozing:

  • { kind: "idle" } — "To'lov kutilmoqda";
  • { kind: "processing"; seconds: number } — "Tekshirilmoqda… (N s)";
  • { kind: "failed"; reason: string } — role="alert" li paragrafda "Rad etildi: " va sabab;
  • { kind: "paid"; amount: number; items: number } — "To'landi: 70000 so'm". Yonida items > 1 bo'lsa " (2 ta taom)" qo'shimchasi. Tuzoqqa e'tibor: items && … emas.

switch va never bilan yozing. App beshta holatni chizsin: idle; processing 3; failed "kartada mablag' yetarli emas"; paid 70000 / 2; paid 5000 / 1.

text
To'lov kutilmoqda
Tekshirilmoqda… (3 s)
Rad etildi: kartada mablag' yetarli emas
To'landi: 70000 so'm (2 ta taom)
To'landi: 5000 so'm

Ishora: «TypeScript bilan: birorta holat unutilmasin» bo'limidagi OrderList — namuna.

Yechim
tsx
type PaymentState =
  | { kind: "idle" }
  | { kind: "processing"; seconds: number }
  | { kind: "failed"; reason: string }
  | { kind: "paid"; amount: number; items: number };

function PaymentStatus({ state }: { state: PaymentState }) {
  switch (state.kind) {
    case "idle":
      return <p>To'lov kutilmoqda</p>;
    case "processing":
      return <p>Tekshirilmoqda… ({state.seconds} s)</p>;
    case "failed":
      return <p role="alert">Rad etildi: {state.reason}</p>;
    case "paid":
      return (
        <p>
          To'landi: {state.amount} so'm
          {state.items > 1 && ` (${state.items} ta taom)`}
        </p>
      );
    default: {
      const unhandled: never = state;
      return unhandled;
    }
  }
}

export default function App() {
  return (
    <>
      <PaymentStatus state={{ kind: "idle" }} />
      <PaymentStatus state={{ kind: "processing", seconds: 3 }} />
      <PaymentStatus
        state={{
          kind: "failed",
          reason: "kartada mablag' yetarli emas",
        }}
      />
      <PaymentStatus
        state={{ kind: "paid", amount: 70000, items: 2 }}
      />
      <PaymentStatus
        state={{ kind: "paid", amount: 5000, items: 1 }}
      />
    </>
  );
}

Ekranda:

text
To'lov kutilmoqda
Tekshirilmoqda… (3 s)
Rad etildi: kartada mablag' yetarli emas
To'landi: 70000 so'm (2 ta taom)
To'landi: 5000 so'm

{state.items > 1 && …} — taqqoslash, shuning uchun items: 1 da hech narsa qo'shilmadi. items && … bo'lsa, items: 0 da 0 chiqib qolardi. never tekshiruvini sinab ko'ring: turga { kind: "refunded" } qo'shing — tsc default dagi qatorda xato beradi, chunki refunded never ga sig'maydi.

4-mashq: Vazifalar qadami

refactor/royxat-react branch'ida src/BelgilanganMatn.tsx, src/OddiyQator.tsx va src/VazifaQatori.tsx ni «Vazifalar qadami» bo'limidagidek yozing. npm run tip va npm run lint toza bo'lsin. Savol: OddiyQator dagi readOnly ni olib tashlasangiz, nima o'zgaradi?

Yechim

tsc va ESLint hech narsa demaydi — readOnly ixtiyoriy atribut. Lekin ro'yxat React'da chizila boshlagach (Ro'yxatlar va key), dev rejimda ogohlantirish chiqadi. Brauzer konsolida «Shartli atributlar» bo'limidagi xabar paydo bo'ladi: You provided a `checked` prop to a form field without an `onChange` handler… — har katak uchun. readOnly React'ga "bu katakni ataylab faqat ko'rsataman" deydi. Hodisalarni boshqarish darsida onChange paydo bo'lganda u o'chiriladi.

10. Real ishda

  • Har ma'lumot so'rovi to'rt holatli — yuklanmoqda, xato, bo'sh va tayyor. Kod ko'rigida birinchi tekshiriladi: "Internet uzilsa nima ko'rinadi?". Keyingi qismlarda TanStack Query kabi kutubxonalar bu holatlarni tayyor beradi — lekin chizish baribir sizning ishingiz.
  • Discriminated union + never — katta loyihalarda holatlarni unutmaslikning standart usuli. TypeScript'li React jamoalarida keng tarqalgan.
  • Bo'sh holat — UX dizaynerlarning alohida mavzusi ("empty state"): bo'sh ro'yxat o'rniga "Hali buyurtma yo'q. Menyuga o'ting!" va tugma — foydalanuvchini keyingi qadamga boshlaydi.
  • Intervyu savollari: "Shartli render usullari qaysilar?", "{count && <X/>} nima uchun xavfli?", "Komponent null qaytarsa nima bo'ladi?".

Xulosa

  • Shart — oddiy JavaScript: if + erta return (butun ko'rinish), ternary (ikkidan biri), && (bor yoki yo'q).
  • && chapida son bo'lmasin: count > 0 &&. Batafsil — JSX II.
  • null — "hech narsa chizma"; yashirish qarorini ko'pincha ota qilgani tushunarliroq.
  • Murakkab shartni return dan oldin o'zgaruvchiga chiqaring — ichma-ich ternary yozmang.
  • Ma'lumotli joy to'rt holatli: yuklanmoqda, xato, bo'sh, tayyor; TypeScript'da discriminated union va never bilan.
  • vazifalar da VazifaQatori — qatorYasa() ning React nusxasi: tahrirda bo'lsa TahrirQatori, aks holda OddiyQator.

Keyingi dars: Ro'yxatlarni render qilish va key — map bilan ro'yxat chizamiz, key nega va qanday tanlanishini ko'ramiz va vazifalar ro'yxatini React'ga beramiz.

Manbalar

  • React: "Conditional Rendering" — react.dev/learn/conditional-rendering
  • React: <input> — "Controlling an input with a state variable", readOnly — react.dev/reference/react-dom/components/input
  • TypeScript Handbook: "Discriminated Unions", "Exhaustiveness checking" — typescriptlang.org/docs/handbook/2/narrowing.html
Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
Shartli render: React'da if, ternary, && va null — yuklanish, xato va bo'sh holatlar — IlmHamroh