React bilan real loyiha arxitekturasi — papkalar tuzilishi

~20 daq · React · Ekotizim va Amaliyot

Muammodan boshlaylik

Loyiha 3 oy oldin boshlangan. Hozir src/ shunday ko'rinadi:

src/
├── components/          (87 ta fayl)
│   ├── Button.jsx
│   ├── ProductCard.jsx
│   ├── CartItem.jsx
│   ├── AdminUserTable.jsx
│   ├── LoginForm.jsx
│   └── ... 82 ta yana
├── hooks/               (34 ta fayl)
├── utils/               (29 ta fayl)
├── api/                 (18 ta fayl)
├── store/               (9 ta fayl)
└── pages/               (22 ta fayl)

Savat funksiyasini o'zgartirish kerak. Qaysi fayllar savatga tegishli? components/ da 87 ta fayl orasidan qidirasiz, keyin hooks/ da, api/ da, store/ da, utils/ da... Besh xil papkada tarqalgan. Savat funksiyasini o'chirish kerak bo'lsa — qaysi fayllarni olib tashlash xavfsiz, hech kim bilmaydi.

Bu — turi bo'yicha guruhlash (by type). Kichik loyihada qulay, katta loyihada — tartibsizlik.


Turi bo'yicha va funksiya bo'yicha

Turi bo'yicha (by type)

src/
├── components/
├── hooks/
├── api/
└── pages/
  • ✅ Oddiy, tushunarli — kichik loyihalar (10–20 komponent) uchun yaxshi
  • ❌ Bitta funksiya fayllari besh papkada
  • ❌ Loyiha o'sgani sari papkalar ulkan bo'ladi

Funksiya bo'yicha (by feature)

src/
├── features/
│   ├── savat/
│   │   ├── components/
│   │   │   ├── SavatQatori.jsx
│   │   │   └── SavatJami.jsx
│   │   ├── hooks/
│   │   │   └── useSavat.js
│   │   ├── api.js
│   │   ├── store.js
│   │   └── index.js
│   ├── katalog/
│   ├── auth/
│   └── buyurtmalar/
├── shared/
│   ├── ui/              // Button, Input, Modal — biznesga bog'liq bo'lmagan
│   ├── hooks/           // useDebounce, useLocalStorage
│   ├── lib/             // formatNarx, sana funksiyalari
│   └── api/             // Axios instance (85-dars)
├── pages/
│   ├── KatalogSahifasi.jsx
│   └── SavatSahifasi.jsx
└── app/
    ├── App.jsx
    ├── router.jsx
    └── providers.jsx
  • ✅ Savat bilan bog'liq hamma narsa — bitta papkada
  • ✅ Funksiyani o'chirish — papkani o'chirish
  • ✅ Jamoada har kim o'z funksiyasida ishlaydi — kamroq to'qnashuvlar
  • ✅ Loyiha o'sganda tuzilma tushunarli qoladi

Redux jamoasi ham, React hamjamiyatining ko'pchiligi ham o'rta va katta loyihalar uchun funksiya bo'yicha tuzilmani tavsiya qiladi (60-dars).


Qatlamlar

Funksiya bo'yicha tuzilmada har bir papkaning o'z vazifasi bor:

Papka Nima Misol
app/ Ilovani ishga tushirish: provider lar, router, global stillar App.jsx, providers.jsx
pages/ Sahifalar — route lar; feature larni yig'adi SavatSahifasi.jsx
features/ Biznes funksiyalar — foydalanuvchi uchun qiymat savat/, auth/, katalog/
shared/ Hech qaysi funksiyaga bog'liq bo'lmagan umumiy kod ui/Button.jsx, lib/formatNarx.js

Import qoidasi — bir yo'nalishda

app  →  pages  →  features  →  shared
  • Yuqoridagi qatlam pastdagini import qila oladi
  • Pastdagi yuqoridagini — yo'q: shared/ hech qachon features/ dan import qilmaydi
  • Feature lar bir-birini to'g'ridan-to'g'ri import qilmaydi (iloji boricha)
// ✅ sahifa feature larni birlashtiradi
// pages/SavatSahifasi.jsx
import { SavatRoyxati } from '@/features/savat';
import { TavsiyaEtilganlar } from '@/features/katalog';

// ❌ feature boshqa feature ning ichiga kirmaydi
// features/savat/components/SavatQatori.jsx
import { MahsulotRasmi } from '@/features/katalog/components/MahsulotRasmi';

Agar ikki feature bir xil narsaga muhtoj bo'lsa — uni shared/ ga ko'chiring yoki sahifada birlashtiring.

[!INFO] Bu g'oyalarning qat'iy, rasmiylashtirilgan versiyasi — Feature-Sliced Design (FSD) metodologiyasi: app, pages, widgets, features, entities, shared qatlamlari va aniq import qoidalari bilan. Katta jamoalarda mashhur. Kichik va o'rta loyihalar uchun yuqoridagi soddalashtirilgan versiya ko'pincha yetarli.


Feature ning ochiq API si — index.js

// features/savat/index.js
export { SavatRoyxati } from './components/SavatRoyxati';
export { SavatBelgisi } from './components/SavatBelgisi';
export { useSavat } from './hooks/useSavat';
// Tashqaridan — faqat index orqali
import { SavatBelgisi, useSavat } from '@/features/savat';

index.js — feature ning "eshigi": tashqariga nima chiqishini belgilaydi. Ichki komponentlar (SavatQatori) yashirin qoladi va ularni bemalol o'zgartirish mumkin.

[!WARNING] shared/ui/index.js kabi juda katta "barrel" fayllar (hamma narsani qayta eksport qiluvchi) muammo tug'dirishi mumkin: bitta Button import qilinganda development serveri butun papkani yuklaydi va ba'zan tree shaking yomonlashadi. Barrel larni feature ning ochiq API si uchun ishlating; katta umumiy kutubxonalarda to'g'ridan-to'g'ri import (@/shared/ui/Button) afzal.


Absolute importlar — alias

// ❌ nisbiy yo'llar
import { Button } from '../../../../shared/ui/Button';

// ✅ alias
import { Button } from '@/shared/ui/Button';
// vite.config.js
import { fileURLToPath, URL } from 'node:url';

export default defineConfig({
  resolve: {
    alias: {
      '@': fileURLToPath(new URL('./src', import.meta.url)),
    },
  },
});
// jsconfig.json (yoki tsconfig.json) — muharrir avtomatik to'ldirishi uchun
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": { "@/*": ["src/*"] }
  }
}

Fayl boshqa papkaga ko'chirilganda importlar buzilmaydi.


Kichik qoidalar

Nomlash

Nima Uslub Misol
Komponent fayli PascalCase SavatQatori.jsx
Hook use + camelCase useSavat.js
Util, api camelCase formatNarx.js, api.js
Papkalar kebab-case yoki camelCase — izchil features/savat/

Testlar va stillar — yonida

features/savat/components/
├── SavatQatori.jsx
├── SavatQatori.test.jsx
└── SavatQatori.module.css

Komponent o'chirilsa — testi va stili ham birga ketadi.

Bitta faylda nechta komponent?

Asosiy qoida — bitta eksport qilinadigan komponent faylda. Faqat shu faylda ishlatiladigan kichik yordamchi komponentlar — o'sha faylda qolishi mumkin.


Qachon nima tanlash

Loyiha Tavsiya
O'quv loyihasi, 10–20 komponent Turi bo'yicha — components/, pages/, hooks/
O'rta loyiha, bir-ikki dasturchi Funksiya bo'yicha — features/, shared/, pages/
Katta loyiha, jamoa Funksiya bo'yicha + qat'iy import qoidalari (ESLint) yoki FSD

[!TIP] Boshidanoq murakkab tuzilma qurmang. Kichik boshlang va loyiha o'sgani sari qayta tuzing: "bu papkada fayllarni topish qiyinlashdi" — qayta tuzish vaqti keldi degan belgi. Import qoidalarini qo'lda kuzatish qiyin — eslint-plugin-boundaries yoki import/no-restricted-paths qoidalari ularni avtomatik tekshiradi.


Nima uchun shunday?

Nima uchun kodni funksiya bo'yicha guruhlash turi bo'yicha guruhlashdan yaxshiroq ishlaydi?

Chunki dasturchi kod bilan vazifalar bo'yicha ishlaydi, fayl turlari bo'yicha emas. "Savatga chegirma qo'shish" vazifasi komponentni, hook ni, API ni va store ni birga o'zgartirishni talab qiladi. Birga o'zgaradigan narsalar birga yashashi kerak — bu dasturlashdagi "cohesion" (bog'liqlik) tamoyili. Turi bo'yicha tuzilma esa birga o'zgaradigan narsalarni ajratib, bir-biriga aloqasi yo'q narsalarni (savat hook i va admin hook i) bitta papkaga qo'yadi. Loyiha kichik bo'lganda bu sezilmaydi; 300 ta faylda esa har bir vazifa "xazina qidirish" ga aylanadi. Yaxshi arxitektura — kodni o'zgartirish oson bo'lgan arxitektura.


Xulosa

Eslab qoling:

  • Turi bo'yicha (components/, hooks/) — kichik loyihalar uchun; o'sganda tartibsizlik
  • Funksiya bo'yicha — features/savat/ ichida komponentlar, hook lar, api, store birga
  • Qatlamlar: app → pages → features → shared; import faqat pastga
  • Feature lar bir-biriga to'g'ridan-to'g'ri kirmaydi; sahifa ularni birlashtiradi
  • index.js — feature ning ochiq API si; katta barrel lardan ehtiyot bo'ling
  • Alias: @/ → src/; testlar va stillar komponent yonida
  • Kichik boshlang, kerak bo'lganda qayta tuzing; qoidalarni ESLint bilan tekshiring

Keyingi dars

89-dars: React bilan real loyiha — API layer, hooks layer, UI layer