IlmHamroh
JavaScript Full-stack/17-qism. React asoslari2/45-dars26 daqiqa
Mundarija (47)

Birinchi React loyiha: Vite shabloni ichida nima bor — index.html → main.tsx → App

Qisqacha: React loyiha bitta buyruq bilan yaratiladi: npm create vite@9.2.1 bahor-menyu -- --template react-ts. Ilova shunday yuklanadi: brauzer index.html ni ochadi, u src/main.tsx ni chaqiradi, main.tsx esa createRoot(#root) bilan App komponentini <div id="root"> ichiga chizadi. StrictMode faqat dev rejimda komponentni ikki marta chaqirib, yashirin xatolarni ko'rsatadi. Bugun vazifalar ga ham birinchi React bo'lagi — "orol" qo'shiladi.

Bu darsda

  • create-vite bilan React + TypeScript loyiha yaratasiz va uni ishga tushirasiz.
  • Shablondagi har faylni o'qiysiz va qaysi biri 16-qismdan tanish ekanini bilasiz.
  • index.html → main.tsx → App zanjirini, createRoot va #root ni tushuntira olasiz.
  • StrictMode nima qilishini o'lchangan misolda ko'rasiz.
  • vazifalar ga React'ni o'rnatib, birinchi komponentni — Izoh orolini qo'shasiz.

Oldin bilishingiz kerak: React nima va nega, Vite I: loyiha yaratish, tsconfig: app va node, ESLint II: React plaginlari.

1. Nega bu kerak?

Oldingi darsda React kodini sayt oynasida ishga tushirdik. Bu qulay, lekin haqiqiy ilova bunday yashamaydi. Haqiqiy ilova — papka: fayllar, paketlar, build, lint. Sardorning birinchi savoli ham shu bo'ldi: "React loyihani qayerdan boshlayman?"

Javob: tayyor shablondan. Buni Vite I darsida vanilla-ts uchun qilgansiz. React shabloni deyarli bir xil — faqat uch-to'rtta yangi fayl qo'shiladi. Bu dars — shu fayllar bo'ylab sayohat.

Sayohatdan keyin bilganingizni vazifalar da ishlatamiz. Uni butunlay qayta yozmaymiz. Ilovaning bitta kichik joyini React'ga beramiz, qolgani vanilla bo'lib qoladi. Bu usul orol (island) deyiladi. Ko'p kompaniyalar eski saytni React'ga aynan shunday, oroldan boshlab ko'chiradi.

Hayotiy o'xshatish: yangi oshxona jihozlari. Butun oshxonani buzib qayta qurish shart emas. Avval bitta plitani almashtirasiz, u ishlasa — keyingisini. Oshxona bir kun ham yopilmaydi.

Maslahat: Chiqishlar 2026-10-13 da olingan: Node 24.21.0, npm 11.19.0, create-vite 9.2.1, Vite 8.3.4, React 19.3.0, Chrome 154. vazifalar qadamidagi chiqishlar — Vite 8.3.3 da. Vaqt (ms), port, hash va papka yo'llari sizda boshqacha bo'ladi.

2. Loyiha yaratish

2.1 npm create vite

npx va npm create darsidan bilasiz: npm create vite create-vite paketini yuklab ishga tushiradi. Savollarni kutmaslik uchun hammasini bir qatorda beramiz:

bash
npm create vite@9.2.1 bahor-menyu -- \
  --template react-ts --no-interactive
text
> npx
> create-vite bahor-menyu --template react-ts --no-interactive

│
◇  Scaffolding project in …\bahor-menyu...
│
└  Done. Now run:

  cd bahor-menyu
  npm install
  npm run dev

react-ts — React + TypeScript. Faqat JavaScript kerak bo'lsa — react. Yana react-compiler-ts shabloni bor: unda React Compiler yoqilgan, uni 18-qismda ko'ramiz. @9.2.1 — aniq versiya: kursdagi natija sizda ham bir xil chiqishi uchun. O'z loyihangizda @latest yozsangiz bo'ladi.

2.2 Paketlarni o'rnatish

Shablon faqat fayllarni yozadi. Paketlarni o'zimiz o'rnatamiz:

bash
cd bahor-menyu
npm install
text
added 27 packages, and audited 28 packages in 12s

9 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

Nimalar o'rnatildi:

bash
npm ls
text
bahor-menyu@0.0.0 …\bahor-menyu
+-- @types/node@24.19.2
+-- @types/react-dom@19.3.0
+-- @types/react@19.3.0
+-- @vitejs/plugin-react@6.1.2
+-- oxlint@1.87.0
+-- react-dom@19.3.0
+-- react@19.3.0
+-- typescript@6.0.3
`-- vite@8.3.4

Bir qiziq narsa. Shablonning package.json ida "react": "^19.2.8" yozilgan, o'rnatilgani esa 19.3.0. Nega? Semver darsini eslang: ^ — "shu major ichida eng yangisi". 19.3.0 2026-09-09 da chiqqan, shablon esa undan oldin yozilgan. Hammasi bo'lib 27 paket, node_modules — 86 MB.

3. Fayllar xaritasi

3.1 Tuzilma

text
bahor-menyu/
├── .gitignore
├── .oxlintrc.json
├── README.md
├── index.html
├── package.json
├── tsconfig.json
├── tsconfig.app.json
├── tsconfig.node.json
├── vite.config.ts
├── public/
│   ├── favicon.svg
│   └── icons.svg
└── src/
    ├── main.tsx
    ├── App.tsx
    ├── App.css
    ├── index.css
    └── assets/  hero.png, react.svg, vite.svg

Yarmidan ko'pi sizga tanish. Qaysi fayl qayerdan:

Fayl Nima Qayerda o'qigansiz
index.html Kirish nuqtasi (entry) Vite I
package.json Paketlar va skriptlar package.json I
tsconfig.*.json (3 ta) TS sozlamasi: app va node tsconfig: app va node
vite.config.ts Vite sozlamasi Vite II
.oxlintrc.json Linter sozlamasi Biome va Oxlint
public/ O'zgarmay ko'chiriladigan fayllar Vite IV
src/assets/ Import qilinadigan rasmlar Vite IV
src/main.tsx, src/App.tsx Yangi: React kodi shu dars

.tsx — ichida JSX bor TypeScript fayl. JSX yo'q faylda .ts yetadi. Brauzer ikkalasini ham tushunmaydi — Vite ularni JavaScript'ga o'giradi.

3.2 package.json

json
{
  "name": "bahor-menyu",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "tsc -b && vite build",
    "lint": "oxlint",
    "preview": "vite preview"
  },
  "dependencies": {
    "react": "^19.2.8",
    "react-dom": "^19.2.8"
  },
  "devDependencies": {
    "@types/node": "^24.13.3",
    "@types/react": "^19.2.18",
    "@types/react-dom": "^19.2.7",
    "@vitejs/plugin-react": "^6.1.1",
    "oxlint": "^1.81.0",
    "typescript": "~6.0.2",
    "vite": "^8.3.0"
  }
}

Ikki paket — dependencies da, chunki ular brauzerga boradi (package.json II):

  • react — komponentlar, useState kabi hooklar, JSX qoidalari. U DOM'ni bilmaydi.
  • react-dom — React daraxtini brauzer DOM'iga chizadigan qism. createRoot shundan.

Nega ikkiga bo'lingan? React faqat brauzer uchun emas. Xuddi o'sha react paketi bilan React Native telefon ekraniga, react-dom/server esa serverda HTML satrga chizadi. react — "nima chizish", react-dom — "qayerga chizish".

build skripti tanish: avval tsc -b turlarni tekshiradi, keyin vite build yig'adi. @types/react — React'ning turlari: useState nima qaytarishini TypeScript shulardan biladi.

Tekshirib ko'ring: Kimdir react-dom ni devDependencies ga ko'chirdi. Build ishlaydimi?

Javob

Ishlaydi. Vite ikkala bo'limdagi paketlarni ham yig'ib dist/ ga yozadi — brauzer uchun farqi yo'q. Lekin bu noto'g'ri belgi: o'qigan dasturchi "bu faqat build asbobi" deb o'ylaydi. Server ilovasida esa (npm ci --omit=dev) react-dom umuman o'rnatilmay qolardi. Qoida o'zgarmaydi: ilova ishlaganda kerak bo'ladigan narsa — dependencies.

4. Ilova qanday yuklanadi

4.1 Zanjir

Avval butun yo'l, keyin har halqa alohida:

flowchart TD
  A["Brauzer: index.html"] --> B["div id=root — bo'sh"]
  A --> C["script: /src/main.tsx"]
  C --> D["createRoot(#root)"]
  D --> E[".render(App)"]
  E --> F["App() — JSX qaytaradi"]
  F --> G["react-dom: DOM elementlar"]
  G --> B

Diagrammadagi asosiy narsa: index.html da #root bo'sh keladi. Ichidagi hamma narsani JavaScript keyin chizadi. Bu — Oldingi darsdagi SPA.

4.2 index.html

html
<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
    <meta name="viewport"
      content="width=device-width, initial-scale=1.0" />
    <title>bahor-menyu</title>
  </head>
  <body>
    <div id="root"></div>
    <script type="module" src="/src/main.tsx"></script>
  </body>
</html>

vanilla-ts shablonidan farqi ikki joyda: <div id="app"> o'rniga <div id="root"> va main.ts o'rniga main.tsx. root — React jamoalaridagi odat, majburiy emas. Muhimi — main.tsx dagi nom bilan bir xil bo'lsin. Darhol lang="en" ni lang="uz" ga almashtiring: ekran o'quvchi (Malika ishlatadigan dastur) matnni o'zbekcha talaffuz qilishi uchun (HTML hujjat tuzilmasi).

4.3 src/main.tsx — React kirish nuqtasi

tsx
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import './index.css'
import App from './App.tsx'

createRoot(document.getElementById('root')!).render(
  <StrictMode>
    <App />
  </StrictMode>,
)

Shablon qo'shtirnoq va nuqtali vergulni boshqa uslubda yozgan — bu Prettier sozlamasiga bog'liq (Prettier), ma'nosi bir xil. Qatorma-qator:

Qator Nima qiladi
import { createRoot } from 'react-dom/client' Brauzer uchun React ildizini yasaydigan funksiya
import './index.css' Umumiy CSS — Vite uni sahifaga ulaydi (Vite IV)
import App from './App.tsx' export default komponent (ESM export)
document.getElementById('root')! Bo'sh <div>; ! — "null emas" (non-null)
createRoot(…) Shu element React'ga beriladi — endi uning ichini React boshqaradi
.render(<StrictMode><App /></StrictMode>) Birinchi chizish: App ni dev tekshiruvi ichida

Ildiz (root) — React boshqaradigan DOM elementi. createRoot dan keyin uning ichiga qo'lda tegmang (oldingi darsdagi uchinchi xato). Ildizdan tashqaridagi narsa esa React'ga tegishli emas — u yerda vanilla kod bemalol ishlayveradi. Orol usuli shunga tayanadi.

O'sha zanjirni sayt oynasida ishga tushiring. Bu blok main.tsx va kichik App ni bitta faylda birlashtiradi:

tsx
import { StrictMode, useState } from "react";
import { createRoot } from "react-dom/client";

function App() {
  const [soni, setSoni] = useState(0);
  return (
    <main>
      <h1>«Bahor» menyusi</h1>
      <p>Buyurtmalar: {soni} ta</p>
      <button onClick={() => setSoni(soni + 1)}>
        Buyurtma berish
      </button>
    </main>
  );
}

createRoot(document.getElementById("root")!).render(
  <StrictMode>
    <App />
  </StrictMode>,
);

Tugma bir marta bosilgach ekranda:

text
«Bahor» menyusi
Buyurtmalar: 1 ta
Buyurtma berish

4.4 src/App.tsx — birinchi komponent

Shablondagi App.tsx 120 qatordan iborat. Uning asosiy qismi (qolgani — havolalar ro'yxati):

tsx
import { useState } from 'react'
import heroImg from './assets/hero.png'
import reactLogo from './assets/react.svg'
import viteLogo from './assets/vite.svg'
import './App.css'

function App() {
  const [count, setCount] = useState(0)

  return (
    <>
      <section id="center">
        <div className="hero">
          <img src={heroImg} className="base" … alt="" />
          <img src={reactLogo} className="framework" … />
          <img src={viteLogo} className="vite" alt="Vite logo" />
        </div>
        …
        <button
          type="button"
          className="counter"
          onClick={() => setCount((count) => count + 1)}
        >
          Count is {count}
        </button>
      </section>
      …
    </>
  )
}

export default App

Hammasi oldingi darsdagi sanoq misoli, faqat bezakli. Yangi ko'rinadigan narsalar va ular qachon o'tiladi:

Kodda Ma'nosi Batafsil
import heroImg from './assets/hero.png' Rasm yo'li — Vite hash'li nom beradi Vite IV, Rasm va assetlar
className="hero" HTML'dagi class — JSX'da className JSX I
<> … </> Fragment — ortiqcha <div> siz bir nechta element JSX II
setCount((count) => count + 1) Updater funksiya — oldingi qiymatdan State II
export default App Faylning asosiy eksporti ESM export

Bularni hozir yodlash shart emas. Har biriga alohida dars bor. Bugun muhimi — fayl qayerdan boshlanib, qayerga borishini bilish.

Tekshirib ko'ring: index.html dagi <div id="root"> ni <div id="ilova"> ga o'zgartirdingiz, main.tsx ga tegmadingiz. Nima bo'ladi?

Javob

getElementById('root') null qaytaradi, createRoot(null) esa xato tashlaydi va sahifa bo'sh qoladi. ! bu yerda yordam bermaydi: u faqat TypeScript'ni jim qiladi, ishlash vaqtida hech narsa tekshirmaydi (non-null). Xatoning aniq matni — «Ko'p uchraydigan xatolar» bo'limida.

5. StrictMode — dev rejimdagi qo'shimcha tekshiruv

5.1 Nima qiladi

StrictMode (qat'iy rejim) — o'zi hech narsa chizmaydigan o'ram komponent. Dev rejimda u ichidagi komponentlarni ikki marta chaqiradi. Nega? React komponent toza funksiya bo'lishini kutadi: bir xil kirish — bir xil natija, yon ta'sirsiz. Ikki marta chaqirilganda iflos komponent o'zini oshkor qiladi.

O'xshatish: oshpaz taomni tatib ko'radi, keyin yana bir marta tatib ko'radi. Ikki safar ta'mi har xil bo'lsa — retseptda nimadir noto'g'ri.

5.2 O'lchab ko'ramiz

Shablondagi App ga bitta qator qo'shdik: console.log('App chizildi, count =', count). Sahifani Chrome'da ochib, tugmani bir marta bosdik. Konsolni ikki rejimda yozib oldik:

Rejim Konsolda
npm run dev App chizildi, count = 0 × 2, keyin count = 1 × 2 — 4 qator
npm run build + vite preview count = 0, keyin count = 1 — 2 qator

Shu kodni sayt oynasida ham ko'rasiz — u yerda ham React'ning dev versiyasi ishlaydi:

tsx
import { StrictMode, useState } from "react";
import { createRoot } from "react-dom/client";

function App() {
  const [soni, setSoni] = useState(0);
  console.log("App chizildi, soni =", soni);
  return (
    <button onClick={() => setSoni(soni + 1)}>Osh +</button>
  );
}

createRoot(document.getElementById("root")!).render(
  <StrictMode>
    <App />
  </StrictMode>,
);

Konsolda (dev rejim, bir bosishdan keyin):

text
App chizildi, soni = 0
App chizildi, soni = 0
App chizildi, soni = 1
App chizildi, soni = 1

Brauzerga React DevTools kengaytmasi o'rnatilgan bo'lsa, takror qatorlar och rangda ko'rinadi — "bu StrictMode'ning takrori" degan belgi. Production build'da takror yo'q: StrictMode u yerda hech narsa qilmaydi va tezlikka ta'sir qilmaydi. Keyinroq o'rganadigan effektlarni (komponent tashqi dunyo bilan ishlaydigan kodni) ham ikki marta ishga tushiradi — buni StrictMode va effektlar darsida o'lchaymiz.

Diqqat: "Ikki marta chiqyapti, xato!" deb StrictMode ni o'chirib qo'ymang. U topgan muammo production'da ham bor — faqat yashirin. Ikki marta chaqirilganda buzilmaydigan komponent yozish to'g'ri yo'l (Pure komponentlar).

6. Sozlama fayllari

6.1 vite.config.ts

ts
import react from '@vitejs/plugin-react'
import { defineConfig } from 'vite'

// https://vite.dev/config/
export default defineConfig({
  plugins: [react()],
})

vanilla-ts dan farqi — bitta plagin (Vite plaginlari). @vitejs/plugin-react 6.1 ikki ish qiladi:

  1. JSX'ni o'giradi. .tsx dagi <App /> ni jsx(App, {}) chaqiruviga aylantiradi. Ichida Oxc ishlaydi — Transpilyatsiya darsidagi Rust'dagi o'giruvchi. Babel endi kerak emas.
  2. Fast Refresh — React uchun HMR. Komponent faylini saqlasangiz, sahifa qayta yuklanmaydi va komponent holati saqlanadi. Buni «Dev server va build» bo'limida o'lchaymiz.

6.2 tsconfig.app.json

Bu faylni tsconfig: app va node darsida qatorma-qator o'qigansiz. Unda React uchun bitta kalit muhim:

jsonc
{
  "compilerOptions": {
    // …
    "jsx": "react-jsx"
  }
}

"react-jsx" — JSX'ni "avtomatik runtime" bilan tekshirish: TypeScript react/jsx-runtime ni o'zi ulaydi deb hisoblaydi. Shuning uchun har faylda import React from 'react' yozish shart emas. Eski kodda bu import har .tsx boshida uchraydi — React 17 gacha majburiy edi.

6.3 Linter: Oxlint yoki ESLint

Shablon sukut bo'yicha Oxlint qo'yadi (Biome va Oxlint). .oxlintrc.json da React'ning ikki qoidasi yoqilgan:

json
{
  "$schema": "./node_modules/oxlint/configuration_schema.json",
  "plugins": ["react", "typescript", "oxc"],
  "rules": {
    "react/rules-of-hooks": "error",
    "react/only-export-components": [
      "warn",
      { "allowConstantExport": true }
    ]
  }
}

npm run lint toza shablonda jim tugaydi (chiqish yo'q, xato kodi 0) — muvaffaqiyat belgisi.

ESLint kerak bo'lsa (ko'p jamoalar hali unda) — --eslint bayrog'i:

bash
npm create vite@9.2.1 bahor-eslint -- \
  --template react-ts --eslint --no-interactive

Bu safar .oxlintrc.json o'rnida eslint.config.js paydo bo'ladi:

js
import js from '@eslint/js'
import globals from 'globals'
import reactHooks from 'eslint-plugin-react-hooks'
import reactRefresh from 'eslint-plugin-react-refresh'
import tseslint from 'typescript-eslint'
import { defineConfig, globalIgnores } from 'eslint/config'

export default defineConfig([
  globalIgnores(['dist']),
  {
    files: ['**/*.{ts,tsx}'],
    extends: [
      js.configs.recommended,
      tseslint.configs.recommended,
      reactHooks.configs.flat.recommended,
      reactRefresh.configs.vite,
    ],
    languageOptions: {
      globals: globals.browser,
    },
  },
])

Bu faylni ESLint II darsida o'qigansiz — u yerdagi bilan bir xil. package.json da esa "lint": "eslint .". vazifalar da ESLint ishlatamiz (16-qismdagi typed linting va XSS qoidalari bor), shuning uchun bugun unga react-hooks plaginini qo'shamiz.

7. Dev server va build

7.1 npm run dev

bash
npm run dev
text
> bahor-menyu@0.0.0 dev
> vite


  VITE v8.3.4  ready in 275 ms

  ➜  Local:   http://localhost:5173/
  ➜  Network: use --host to expose

Brauzerda http://localhost:5173/ ni oching — Vite va React logotiplari va "Count is 0" tugmasi. Server qanday ishlashini Vite I da ko'rgansiz. React'da ikki yangilik bor. Birinchisi: dev server index.html ning <head> boshiga Fast Refresh uchun skript qo'shadi (curl -s http://localhost:5173/ bilan ko'rdik):

text
<!doctype html>
<html lang="en">
  <head>
    <script type="module">import { injectIntoGlobalHook } from "/@react-refresh";
injectIntoGlobalHook(window);
window.$RefreshReg$ = () => {};
window.$RefreshSig$ = () => (type) => type;</script>

    <script type="module" src="/@vite/client"></script>

Ikkinchisi: brauzer /src/main.tsx ni so'raganda, JSX allaqachon o'girilgan bo'ladi. Javobdan bo'lak (importlar va oxiri … bilan qisqartirildi; qator uzun — yon tomonga suring):

text
createRoot(document.getElementById("root")).render(/* @__PURE__ */ _jsxDEV(StrictMode, { children: /* @__PURE__ */ _jsxDEV(App, {}, void 0, false, {
	fileName: _jsxFileName,
	lineNumber: 8,
	columnNumber: 5
}, this) }, void 0, false, {
…

<StrictMode><App /></StrictMode> — oddiy funksiya chaqiruvlariga aylandi. ! o'chib ketdi — u faqat TypeScript uchun edi. fileName va lineNumber — dev'dagi xato xabarlari uchun: React xatoni qaysi fayl, qaysi qatordagi komponentda bo'lganini aytadi. Bu o'giruvning to'liq qoidalarini JSX I darsida ko'ramiz.

7.2 Fast Refresh: holat saqlanadi

Tajriba (headless Chrome 154): "Count is" tugmasini 3 marta bosdik, keyin App.tsx dagi Get started matnini Xush kelibsiz ga o'zgartirib, faylni saqladik. 2 soniyadan keyin sahifada:

Sarlavha Tugma Sahifa qayta yuklandimi
Saqlashdan oldin Get started Count is 3 —
Saqlashdan keyin Xush kelibsiz Count is 3 yo'q

Terminalda — [vite] (client) hmr update /src/App.tsx. Matn yangilandi, count esa 3 da qoldi. Vite I darsida oddiy .ts modul o'zgarganda sahifa to'liq qayta yuklangan edi — holat yo'qolgan edi. Fast Refresh komponentni almashtiradi, lekin uning holatini saqlaydi. Formani to'ldirib turib uslubni tuzatayotganingizda bu katta qulaylik.

Maslahat: Fast Refresh faqat fayl faqat komponentlar eksport qilganda ishlaydi. Faylda komponent bilan birga oddiy funksiya yoki o'zgarmas ham eksport qilinsa — sahifa to'liq qayta yuklanadi. only-export-components qoidasi aynan shuni ogohlantiradi.

7.3 npm run build: bo'sh React qancha turadi

bash
npm run build
text
> bahor-menyu@0.0.0 build
> tsc -b && vite build

vite v8.3.4 building client environment for production...
transforming...
✓ 20 modules transformed.
rendering chunks...
computing gzip size...
dist/index.html                   0.46 kB │ gzip:  0.29 kB
dist/assets/react-CHdo91hT.svg    4.12 kB │ gzip:  2.06 kB
dist/assets/vite-BF8QNONU.svg     8.70 kB │ gzip:  1.60 kB
dist/assets/hero-CLDdwZDr.png    13.05 kB
dist/assets/index-D64VDMd1.css    4.10 kB │ gzip:  1.47 kB
dist/assets/index-CVtPK4EU.js   222.44 kB │ gzip: 69.28 kB

✓ built in 159ms

Bitta sanoq tugmasi — 222 KB JavaScript (gzip 69 KB). vanilla-ts shablonida xuddi shunday tugma — 4.49 KB (gzip 2.02). Farq — React va react-dom ning o'zi. Oldingi darsda aytilgan "kirish narxi" mana shu.

8. Vazifalar qadami: React oroli

8.1 Reja

vazifalar v6 — vanilla ilova. Bugun uning bitta joyini React'ga beramiz: sahifa pastidagi izoh matni ("v3: ro'yxat shu brauzerda…"). Bu eng xavfsiz joy: holati yo'q, hodisasi yo'q. Maqsad — React'ni loyihaga ulash: paketlar, TypeScript, Vite, ESLint, build va 159 ta brauzer tekshiruvi. Komponent esa hozircha oddiy.

flowchart TD
  H["index.html"] --> V["asosiy.ts — vanilla"]
  H --> M["main.tsx — React"]
  V --> R1["forma, ro'yxat, filtr, qidiruv"]
  M --> I["div id=izoh — Izoh komponenti"]

Ikki skript yonma-yon: vanilla qism o'z elementlarini, React esa faqat #izoh ni boshqaradi. Ular bir-biriga tegmaydi. Keyingi darslarda React'ning hududi kengayib boradi. Mini-ilova darsida butun interfeys React'da bo'ladi.

Yangi branch: build/react.

8.2 Paketlar

vazifalar ning .npmrc sida save-exact=true bor (.npmrc). Shuning uchun versiyalar ^ siz yoziladi:

bash
npm i react@19.3.0 react-dom@19.3.0
text
added 3 packages, and audited 224 packages in 1s

81 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

Uchta: react, react-dom va uning bog'liqligi scheduler (React ishni bo'laklarga bo'lib bajaradigan rejalashtiruvchi). Endi build va tekshiruv uchun:

bash
npm i -D @types/react@19.3.0 @types/react-dom@19.3.0 \
  @vitejs/plugin-react@6.1.2 eslint-plugin-react-hooks@7.1.1
text
added 41 packages, and audited 265 packages in 9s

85 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

Shablondagidan ikki farq bor. Birinchisi — aniq versiyalar (19.3.0, ^ siz). Ikkinchisi — eslint-plugin-react-hooks qo'shildi: vazifalar da Oxlint emas, ESLint. Plaginning 7.1.1 versiyasi ESLint 10 bilan mos: ERESOLVE yo'q (ESLint II dagi peer tuzog'i bu safar chiqmadi). O'rnatishda skript bajaradigan paket yo'q (npm query ":attr(scripts, [install])" → []) — ta'minot zanjiri tekshiruvi.

8.3 Birinchi komponent: src/Izoh.tsx

tsx
export function Izoh() {
  return (
    <p>
      <small>
        v3: ro'yxat shu brauzerda va «Bahor» mashq serverida
        saqlanadi. Server — o'rganish uchun: u qayta ishga tushsa,
        ro'yxat shu brauzerdagi nusxadan tiklanadi.
      </small>
    </p>
  );
}

Matn — v6 dagi index.html dan aynan ko'chirilgan. Foydalanuvchi farqni sezmasligi kerak. JSX matndagi qator ko'chishlarini bitta bo'sh joyga aylantiradi — matnni qanday bo'lib yozsangiz ham ekranda bitta paragraf. Faylning boshida uch qatorli izoh bor: "komponent — JSX qaytaradigan funksiya; nomi katta harf bilan (kichik harfli <izoh> ni React oddiy HTML teg deb oladi)". Kursdagi kod bloklarida telefon ekraniga sig'maydigan uzun izoh qatorlarini tushirib qoldiramiz — mazmuni matnda.

8.4 Kirish nuqtasi: src/main.tsx

tsx
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import { Izoh } from "./Izoh.tsx";

const ildiz = document.getElementById("izoh");
if (ildiz === null) {
  throw new TypeError("#izoh topilmadi");
}
createRoot(ildiz).render(
  <StrictMode>
    <Izoh />
  </StrictMode>,
);

Fayldagi izohlar: "React faqat o'zi olgan bitta elementni boshqaradi — orol (island)" va "StrictMode — faqat dev'da". Shablondan farqi: ! o'rniga aniq tekshiruv. Element topilmasa — o'zimizning tushunarli xato, React'ning umumiy xabari emas. Bu toraytirish — if dan keyin TypeScript ildiz ni HTMLElement deb biladi.

index.html da eski <p> o'rniga bo'sh "joy" va yangi skript:

diff
+  <script type="module" src="src/main.tsx"></script>
 </head>
 …
-    <p><small>v3: ro'yxat shu brauzerda va «Bahor» mashq
-      serverida saqlanadi. Server — o'rganish uchun: u qayta
-      ishga tushsa, ro'yxat shu brauzerdagi nusxadan
-      tiklanadi.</small></p>
+    <!-- React oroli (17/#02): ichini src/main.tsx chizadi -->
+    <div id="izoh"></div>

8.5 TypeScript: jsx bayrog'i

Fayllarni qo'shib, npm run tip ni ishga tushirdik — tsconfig.app.json ga hali tegmagan edik:

text
> tip
> tsc -b

src/Izoh.tsx(6,5): error TS17004: Cannot use JSX unless the '--jsx' flag is provided.
src/Izoh.tsx(7,7): error TS17004: Cannot use JSX unless the '--jsx' flag is provided.
src/main.tsx(6,22): error TS6142: Module './Izoh.tsx' was resolved to '…/src/Izoh.tsx', but '--jsx' is not set.
src/main.tsx(15,3): error TS17004: Cannot use JSX unless the '--jsx' flag is provided.
src/main.tsx(16,5): error TS17004: Cannot use JSX unless the '--jsx' flag is provided.

Tarjima: "--jsx bayrog'i berilmaguncha JSX ishlatib bo'lmaydi." TypeScript .tsx faylni ko'rdi ("include": ["src"]), lekin JSX'ni qanday tushunishni bilmaydi. Tuzatish — shablondagi kalit:

diff
+    "jsx": "react-jsx",

Ustidagi izoh: "<Izoh /> → jsx() chaqiruvi, react/jsx-runtime dan avtomatik import". Shundan keyin npm run tip jim tugaydi.

8.6 Vite va ESLint

vite.config.ts ga plagin — shablondagidek:

diff
+import react from "@vitejs/plugin-react";
 …
     plugins: [
+      react(),
       qobiqPlagini(),

eslint.config.js da uch o'zgarish. Birinchisi — files naqshlariga tsx qo'shildi ("**/*.{ts,tsx}"), aks holda yangi fayllar tekshirilmasdi. Ikkinchisi — React hooklar plagini (izohi qisqartirilgan):

js
  {
    // React qoidalari (17/#02): hooklar qoidasi, effekt
    // bog'liqliklari va React Compiler tahlili asosidagi qoidalar
    files: ["src/**/*.{ts,tsx}"],
    extends: [reactHooks.configs.flat.recommended],
  },

Uchinchisi — XSS himoyasi (XSS va DOM xavfsizligi). vazifalar da innerHTML allaqachon taqiqlangan. React'da HTML'ni to'g'ridan-to'g'ri yozishning bitta yo'li bor — dangerouslySetInnerHTML atributi. Uni ham taqiqlaymiz:

js
// no-restricted-syntax ro'yxatiga yangi element
{
  // React'dagi innerHTML (17/#02): JSX matnni o'zi ekranlaydi,
  // HTML faqat shu atribut orqali kiradi
  selector: "JSXAttribute[name.name='dangerouslySetInnerHTML']",
  message: "XSS: matnni JSX ichida {matn} qilib yozing.",
},

Sinab ko'rdik — vaqtinchalik src/Xavf.tsx da <p dangerouslySetInnerHTML={{ __html: matn }} />:

bash
npx eslint src/Xavf.tsx
text
…\src\Xavf.tsx
  2:13  error  XSS: matnni JSX ichida {matn} qilib yozing  no-restricted-syntax

✖ 1 problem (1 error, 0 warnings)

JSX'da {matn} doim matn bo'lib chiqadi: <b> yozilgan satr ekranda <b> harflari bo'lib ko'rinadi, qalin shrift bo'lmaydi. Bu — React'ning sukut bo'yicha XSS himoyasi (JSX II da sinaymiz).

Yana ikki kichik o'zgarish. package.json da "lint": "eslint . --max-warnings=0": ogohlantirish ham xato hisoblanadi. Hooklar qoidalarining bir qismi "warn" darajasida — ular jim o'tib ketmasin. .lintstagedrc.json da "*.{js,ts,tsx}" — commit oldidan .tsx ham tekshiriladi (Husky va lint-staged).

8.7 Build va tekshiruvlar

bash
npm run build
text
vite v8.3.3 building client environment for production...
transforming...
<script src="assets/js/tema.js"> in "/index.html" can't be bundled without type="module" attribute
✓ 35 modules transformed.
rendering chunks...
computing gzip size...
dist/index.html                   5.16 kB │ gzip:  1.84 kB
dist/assets/index-BI1hyTgJ.css    3.59 kB │ gzip:  1.29 kB
dist/assets/js/tema.js            0.16 kB │ gzip:  0.15 kB │ map:     0.94 kB
dist/assets/olchov-G4bloHwN.js    8.92 kB │ gzip:  3.42 kB │ map:    22.87 kB
dist/assets/index-BD8i4HYm.js   244.82 kB │ gzip: 77.81 kB │ map: 1,160.66 kB
✓ built in 804ms
sw.js: QOBIQ — 12 ta, VERSIYA — v6-88dfa28a

tema.js haqidagi ogohlantirish 16-qismdan tanish — u ataylab oddiy skript. Vite ikki modul skriptini (asosiy.ts va main.tsx) bitta index-….js ga yig'di.

Brauzer yuklaydigan JS + CSS (16-qismdagi o'lchov skripti bilan):

Xom gzip
v6 (vanilla) 38 066 B 14 279 B
Bugun (React oroli) 257 503 B 81 691 B

Bitta <p> uchun +67 KB gzip. Qimmat — lekin bu bir martalik narx: keyingi komponentlar deyarli hech narsa qo'shmaydi. Qism oxirida, butun ilova React'da bo'lganda, jami 83.2 KB bo'ladi.

Qolgan tekshiruvlar: npm test — 146/146, npm run lint, npm run format:check, npm run tip — toza. 159 ta brauzer tekshiruvi (dist/ da, CSP va Trusted Types bilan) — 159/159. Foydalanuvchi uchun hech narsa o'zgarmadi.

8.8 CSP va Fast Refresh

vazifalar da CSP bor: script-src 'self' — HTML ichidagi skript taqiqlangan (CSP). Dev server qo'shadigan Fast Refresh skripti esa aynan HTML ichida (inline). Dev'da buzilish bo'lmaydimi?

Tekshirdik: CSP buzilishi 0, Fast Refresh ishlaydi (Izoh.tsx dagi matnni o'zgartirganda sahifa qayta yuklanmadi). Sababi — skript qayerga qo'yilganida. Vite uni <head> ning eng boshiga, CSP <meta> dan oldin yozadi. <meta> dagi CSP esa faqat o'zidan keyingi elementlarga ta'sir qiladi. Production build'da bu skript umuman yo'q.

Commit:

text
build: React 19.3 va plugin-react — birinchi komponent (Izoh oroli)

Diff: 9 fayl (lock bilan), PR — 16-qismdagidek, gh pr merge --merge.

9. Ko'p uchraydigan xatolar

9.1 Target container is not a DOM element.

index.html da id="root", main.tsx da esa boshqa nom:

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

function App() {
  return <p>«Bahor» menyusi</p>;
}

// index.html da <div id="root">, biz esa "app" deb yozdik
createRoot(document.getElementById("app")!).render(<App />);

Konsolda:

text
Uncaught Error: Target container is not a DOM element.

Tarjima: "Nishon konteyner DOM elementi emas." getElementById("app") null qaytardi, createRoot esa haqiqiy element kutadi. TypeScript jim — ! uni ishontirdi. Tuzatish: nomlarni bir xil qiling yoki vazifalar dagidek if (ildiz === null) tekshiruvini yozing.

9.2 Cannot use JSX unless the '--jsx' flag is provided.

Mavjud TypeScript loyihasiga React qo'shganda tsconfig.app.json ga "jsx": "react-jsx" yozilmagan. «Vazifalar qadami» dagi to'liq misolni ko'ring.

9.3 Could not read package.json

npm run dev ni loyiha papkasidan tashqarida ishga tushirish:

text
npm error code ENOENT
npm error syscall open
npm error path …\package.json
npm error errno -4058
npm error enoent Could not read package.json: Error: ENOENT: no such file or directory, open '…\package.json'

npm package.json ni joriy papkadan qidiradi. npm create dan keyin cd bahor-menyu ni unutmang.

9.4 index.html ni ikki marta bosib ochish

Sahifa bo'sh, konsolda modul xatosi. Brauzer .tsx ni bajara olmaydi va file:// dan modul yuklamaydi (Asboblar zanjiri). Dev'da — npm run dev, build natijasini ko'rish uchun — npm run preview.

9.5 StrictMode ni "tuzatish" uchun o'chirish

Konsolda har narsa ikki marta chiqadi — bu xato emas. «StrictMode — dev rejimdagi qo'shimcha tekshiruv» bo'limidagi o'lchovni eslang.

10. Mashqlar

Mashq papkasi: kurs/mashqlar/17/02-birinchi-loyiha/. Loyihani «Loyiha yaratish» bo'limidagidek yarating.

1-mashq (oson): shablonni o'qing

Loyihani yaratib, npm run dev ni ishga tushiring va javob bering:

  • React chizadigan element index.html da qanday id bilan:
  • createRoot qaysi paketdan import qilinadi:
  • StrictMode takrori qaysi buyruqda ko'rinmaydi — npm run dev yoki npm run preview:
Yechim

root — <div id="root">. createRoot — react-dom/client dan: DOM bilan ishlash react-dom ning vazifasi, react esa DOM'ni bilmaydi. npm run preview — u production build'ni ko'rsatadi, StrictMode esa faqat dev'da ikki marta chaqiradi.

2-mashq (o'rta): «Bahor» menyusi

Shablondagi App.tsx ni tozalang (rasm va CSS importlari kerak emas) va «Bahor» menyusini chizing. Karta uchun alohida fayl — src/MenuCard.tsx. Unda MenuCard komponenti bo'lsin, props: name: string va price: number. Bu — oldingi darsdagi MenuCard ning TypeScript varianti. App to'rtta karta chizsin: osh 35000, lag'mon 28000, manti 30000, ko'k choy 5000. Props turi — oddiy type (type va interface). Natijani npm run dev da tekshiring, keyin npm run build va npm run lint toza bo'lsin.

Yechim

src/MenuCard.tsx:

tsx
// MenuCard.tsx — bitta taom kartasi (17/02, 2-mashq)
type MenuCardProps = { name: string; price: number };

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

src/App.tsx:

tsx
// App.tsx — «Bahor» menyusi (17/02, 2-mashq)
import { MenuCard } from "./MenuCard.tsx";

export default function App() {
  return (
    <main>
      <h1>«Bahor» menyusi</h1>
      <ul>
        <MenuCard name="Osh" price={35000} />
        <MenuCard name="Lag'mon" price={28000} />
        <MenuCard name="Manti" price={30000} />
        <MenuCard name="Ko'k choy" price={5000} />
      </ul>
    </main>
  );
}

Ikki fayl bitta blokda — sayt oynasida sinash uchun:

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

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

export default function App() {
  return (
    <main>
      <h1>«Bahor» menyusi</h1>
      <ul>
        <MenuCard name="Osh" price={35000} />
        <MenuCard name="Lag'mon" price={28000} />
        <MenuCard name="Manti" price={30000} />
        <MenuCard name="Ko'k choy" price={5000} />
      </ul>
    </main>
  );
}

Ekranda:

text
«Bahor» menyusi
Osh — 35000 so'm
Lag'mon — 28000 so'm
Manti — 30000 so'm
Ko'k choy — 5000 so'm

src/assets/ va App.css ni o'chirsangiz ham build buzilmaydi — ular faqat App.tsx dan import qilingan edi. npm run build — JS 220.17 KB (gzip 68.86): rasm va ko'p CSS ketdi, React narxi qoldi.

3-mashq (qiyin): ikkinchi orol

Sahifada ikkita mustaqil React ildizi bo'lsin. index.html da #root dan keyin <footer id="ish-vaqti"></footer>. src/IshVaqti.tsx — "Ish vaqti: 07:00–23:00. Hozir: ochiq" matni va "Almashtir" tugmasi (bosilganda "ochiq" ↔ "yopiq"; useState(true) va ternary operator). main.tsx da ikkinchi createRoot. Tekshiring: "Almashtir" bosilganda menyu o'zgarmaydi.

Yechim

src/IshVaqti.tsx:

tsx
// IshVaqti.tsx — ikkinchi React "orol" (17/02, 3-mashq)
import { useState } from "react";

export function IshVaqti() {
  const [ochiq, setOchiq] = useState(true);
  return (
    <p>
      Ish vaqti: 07:00–23:00. Hozir: {ochiq ? "ochiq" : "yopiq"}
      {" "}
      <button onClick={() => setOchiq(!ochiq)}>Almashtir</button>
    </p>
  );
}

src/main.tsx:

tsx
// main.tsx — ikki ildiz: #root va #ish-vaqti (17/02, 3-mashq)
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import "./index.css";
import App from "./App.tsx";
import { IshVaqti } from "./IshVaqti.tsx";

createRoot(document.getElementById("root")!).render(
  <StrictMode>
    <App />
  </StrictMode>,
);

createRoot(document.getElementById("ish-vaqti")!).render(
  <StrictMode>
    <IshVaqti />
  </StrictMode>,
);

{" "} — matn va tugma orasidagi bo'sh joy: JSX qator oxiridagi bo'shliqni tashlab yuboradi (JSX II da). Biz vite preview da headless Chrome bilan tekshirdik: "Almashtir" bosilgach #ish-vaqti "yopiq" bo'ldi, #root matni o'zgarmadi, konsolda xato yo'q. Ikki ildiz — ikki alohida React daraxti: biri ikkinchisining holatini ko'rmaydi. Bitta sahifada bir nechta orol — eski saytni ko'chirishning odatiy usuli. vazifalar da hozir bitta orol bor, Ro'yxatlar va key darsida ikkinchisi (ro'yxat) qo'shiladi.

4-mashq: Vazifalar qadami

vazifalar da build/react branch'ini oching va «Vazifalar qadami: React oroli» bo'limidagi o'zgarishlarni kiriting: paketlar, Izoh.tsx, main.tsx, index.html, tsconfig.app.json (jsx), vite.config.ts, eslint.config.js, package.json (--max-warnings=0), .lintstagedrc.json. Keyin npm run check va npm run build toza bo'lsin, npm run dev da izoh matni avvalgidek ko'rinsin.

Yechim

Tekshiruv ro'yxati:

  • npm run tip — TS17004 bo'lsa, jsx kaliti unutilgan.
  • npm run lint — .tsx fayllar ham tekshiriladimi? files naqshlarida tsx bormi?
  • npm run build — index-….js taxminan 245 KB (gzip ~78). Bundan ancha kichik bo'lsa — main.tsx index.html ga ulanmagan.
  • npm test — 146/146 (sof mantiq testlari React'dan bexabar).
  • Brauzerda: izoh matni pastda, DevTools Elements'da <div id="izoh"><p><small>… — React chizgan.

Yakuniy kod — build: React 19.3 va plugin-react — birinchi komponent (Izoh oroli) commit'i. PR'ni birlashtiring.

11. Real ishda

  • Yangi loyiha: ishda React loyihani noldan kamdan-kam yaratasiz — ko'pincha tayyor repo beriladi. Lekin uning ichida aynan shu fayllar: main.tsx, App.tsx, vite.config.ts, uchta tsconfig. Bugungi xarita begona loyihada ham ishlaydi (Begona repoda orientatsiya).
  • Orol usuli: eski saytni (PHP, jQuery, Django shablonlari) React'ga ko'chirish ko'pincha bitta createRoot dan boshlanadi. Butun sayt qayta yozilmaydi.
  • Intervyuda: "react va react-dom farqi?", "StrictMode nima qiladi va nega konsolda ikki marta chiqadi?", "Create React App o'rniga nima ishlatiladi?" (javob: Vite yoki framework).
  • Kod ko'rib chiqishda: dangerouslySetInnerHTML va o'chirib qo'yilgan StrictMode — tajribali dasturchi birinchi qaraydigan joylar.

Xulosa

  • npm create vite@9.2.1 <nom> -- --template react-ts — React + TypeScript loyiha; keyin npm install va npm run dev.
  • Zanjir: index.html (<div id="root">) → src/main.tsx (createRoot(...).render(...)) → App komponenti.
  • react — komponentlar va hooklar, react-dom — ularni brauzer DOM'iga chizish.
  • StrictMode dev'da komponentni ikki marta chaqiradi (o'lchandi: 4 qator va 2 qator), production'da hech narsa qilmaydi.
  • @vitejs/plugin-react — JSX o'girish (Oxc) va Fast Refresh (holat saqlanadi); tsconfig da "jsx": "react-jsx".
  • vazifalar da React — #izoh oroli: bundle 14.3 → 81.7 KB gzip, testlar 146/146, brauzer 159/159.

Keyingi dars: JSX I: JSX aslida JavaScript — <App /> qanday qilib jsx() chaqiruviga aylanishini ko'ramiz va JSX'ning hamma qoidalari shundan kelib chiqishini tushunamiz.

Manbalar

  • React hujjatlari: "Build a React app from Scratch", "createRoot", "StrictMode" — react.dev
  • Vite: "Getting Started" (npm create vite, shablonlar) — vite.dev/guide; create-vite — github.com/vitejs/vite/tree/main/packages/create-vite
  • @vitejs/plugin-react — github.com/vitejs/vite-plugin-react
  • eslint-plugin-react-hooks — react.dev/reference/eslint-plugin-react-hooks
Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
Birinchi React loyiha: Vite shabloni ichida nima bor — index.html → main.tsx → App — IlmHamroh