BrowserRouter, Routes, Route — tuzilishi

~15 daq · React · Routing

Muammodan boshlaylik

39-darsda React Router ni o'rnatdik va birinchi ilovani yozdik. Hamma narsa ishladi. Lekin bir nechta savol qoldi:

  • Nima uchun BrowserRouter ni main.jsx da yozdik, App.jsx da emas?
  • Routes ichida Route lar aniq ketma-ketlikda turadimi?
  • /mahsulotlar va /mahsulotlar/yangi — ikkalasi ham mos kelib qolsa nima bo'ladi?
  • Bir nechta Routes bloki bo'lishi mumkinmi?

Bu darsda shu savollarga javob beramiz — BrowserRouter, Routes va Route ning ichki mexanizmlarini chuqurroq tushunib olamiz.


BrowserRouter qanday ishlaydi?

BrowserRouter — bu oddiy React komponent. U ichki React Context yaratib, URL ma'lumotini barcha farzand komponentlarga uzatadi.

Shuning uchun Link, useNavigate, useParams kabi barcha React Router elementlari BrowserRouter ichida bo'lishi shart — ular o'sha kontekstdan ma'lumot oladi.

Hayotiy o'xshatma: BrowserRouter — shaharning asosiy pochta bo'limi. Har bir xonadon (komponent) o'z manzilini undan oladi. Pochta bo'limi bo'lmasa — hech qaysi xonadon o'z manzilinni bilmaydi.


BrowserRouter ni qayerga qo'yish kerak?

Qoidasi oddiy: barcha routing elementlarni o'rab oladigan eng tashqi komponentda bo'lishi kerak.

Odatda ikki xil yondashuv mavjud:

Variant 1 — main.jsx da:

// main.jsx
import { BrowserRouter } from 'react-router-dom';
import App from './App';

ReactDOM.createRoot(document.getElementById('root')).render(
  <BrowserRouter>
    <App />
  </BrowserRouter>
);
// App.jsx — faqat Routes va komponentlar
import { Routes, Route } from 'react-router-dom';

function App() {
  return (
    <Routes>
      <Route path="/" element={<Bosh />} />
      <Route path="/haqida" element={<Haqida />} />
    </Routes>
  );
}

Variant 2 — App.jsx da:

// main.jsx — oddiy
import App from './App';

ReactDOM.createRoot(document.getElementById('root')).render(<App />);
// App.jsx — BrowserRouter shu yerda
import { BrowserRouter, Routes, Route } from 'react-router-dom';

function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<Bosh />} />
        <Route path="/haqida" element={<Haqida />} />
      </Routes>
    </BrowserRouter>
  );
}

Qaysi variant to'g'ri? Ikkalasi ham ishlaydi. Lekin birinchi variant — main.jsx da — ko'proq tarqalgan. Sababi: App.jsx ni test qilish osonlashadi (test vaqtida boshqa Router turini o'rab qo'ysa bo'ladi, masalan MemoryRouter).


Routes qanday ishlaydi?

Routes — "tarjimon". U joriy URL ni oladi va ichidagi barcha Route larni yuqoridan pastga ko'rib chiqadi. Birinchi mos kelganini tanlaydi va faqat o'shanisini render qiladi.

<Routes>
  <Route path="/" element={<Bosh />} />
  <Route path="/haqida" element={<Haqida />} />
  <Route path="/mahsulotlar" element={<Mahsulotlar />} />
  <Route path="*" element={<TopilmadI />} />
</Routes>

URL /haqida bo'lsa:

  1. "/" — mos keladimi? v6 da aniq moslashish bo'ladi, shuning uchun yo'q
  2. "/haqida" — mos keladi! <Haqida /> render bo'ladi
  3. Qolganlar tekshirilmaydi

Bu v5 dan farqli: v5 da <Switch> ketma-ket tekshirar va exact kalit so'zi kerak edi. v6 da bu avtomatik.


v5 va v6 farqi — muhim

Agar internetda eski qo'llanmalarni ko'rsangiz, shunday kod ko'rasiz:

// ❌ Bu v5 — hozir ishlamaydi
import { Switch, Route } from 'react-router-dom';

<Switch>
  <Route exact path="/" component={Bosh} />
  <Route path="/haqida" component={Haqida} />
</Switch>

v6 da:

  • <Switch> → <Routes> ga o'zgartirildi
  • component={...} → element={<Komponent />} ga o'zgartirildi
  • exact prop yo'q — v6 da avtomatik aniq moslashish
// ✅ Bu v6 — to'g'ri
import { Routes, Route } from 'react-router-dom';

<Routes>
  <Route path="/" element={<Bosh />} />
  <Route path="/haqida" element={<Haqida />} />
</Routes>

Route — batafsil

Route — bitta qoidani belgilaydi: "bu URL bo'lsa, bu komponentni ko'rsat."

path prop

URL manzilini bildiradi. Bir nechta xil yozilishi mumkin:

{/* Aniq manzil */}
<Route path="/mahsulotlar" element={<Mahsulotlar />} />

{/* Dinamik parametr — : bilan */}
<Route path="/mahsulot/:id" element={<MahsulotDetali />} />

{/* Bir nechta parametr */}
<Route path="/kategoriya/:slug/mahsulot/:id" element={<Detali />} />

{/* Istalgan qolgan manzil — 404 */}
<Route path="*" element={<TopilmadI />} />

element prop

Ko'rsatiladigan komponentni bildiradi. JSX ko'rinishida yoziladi:

{/* ✅ To'g'ri — JSX */}
<Route path="/haqida" element={<Haqida />} />

{/* ❌ Xato — komponent sifatida */}
<Route path="/haqida" element={Haqida} />

{/* ❌ Xato — v5 usuli */}
<Route path="/haqida" component={Haqida} />

Nima uchun JSX? Chunki element={<Haqida />} ko'rinishida props uzatish oson bo'ladi:

<Route path="/profil" element={<Profil foydalanuvchi={joriyFoydalanuvchi} />} />

Index Route — bosh sahifa uchun maxsus yondashuv

Nested routing (ichma-ich) da bosh sahifani ko'rsatish uchun index prop ishlatiladi:

<Routes>
  <Route path="/dashboard" element={<Dashboard />}>
    <Route index element={<DashboardBosh />} />          {/* /dashboard */}
    <Route path="statistika" element={<Statistika />} /> {/* /dashboard/statistika */}
    <Route path="sozlamalar" element={<Sozlamalar />} /> {/* /dashboard/sozlamalar */}
  </Route>
</Routes>

index prop li Route — path yo'q, lekin ota Route ning URL iga to'g'ri kelganda ko'rsatiladi. Bu nested routing da foydali — 45-darsda batafsil ko'ramiz.


Bir nechta Routes bloki

Odatda bir ilovada bitta <Routes> bloki bo'ladi. Lekin bir nechta ham bo'lishi mumkin — masalan, bir xil sahifada ikkita mustaqil panel:

function App() {
  return (
    <div className="layout">
      {/* Asosiy panel */}
      <main>
        <Routes>
          <Route path="/" element={<Bosh />} />
          <Route path="/mahsulotlar" element={<Mahsulotlar />} />
        </Routes>
      </main>

      {/* Yon panel — o'z route lari bilan */}
      <aside>
        <Routes>
          <Route path="/mahsulotlar" element={<FiltrPanel />} />
        </Routes>
      </aside>
    </div>
  );
}

/mahsulotlar da asosiy panel ham, yon panel ham ko'rsatiladi. Bosh sahifada faqat asosiy panel ko'rinadi. Bu kamdan-kam ishlatiladi, lekin mumkin.


To'liq misol — barcha tushunchalar bilan

// src/App.jsx
import { Routes, Route } from 'react-router-dom';
import Nav from './components/Nav';
import Bosh from './pages/Bosh';
import Haqida from './pages/Haqida';
import Mahsulotlar from './pages/Mahsulotlar';
import MahsulotDetali from './pages/MahsulotDetali';
import TopilmadI from './pages/TopilmadI';

function App() {
  return (
    <>
      <Nav />

      <Routes>
        {/* Bosh sahifa */}
        <Route path="/" element={<Bosh />} />

        {/* Oddiy sahifalar */}
        <Route path="/haqida" element={<Haqida />} />

        {/* Ro'yxat sahifasi */}
        <Route path="/mahsulotlar" element={<Mahsulotlar />} />

        {/* Dinamik sahifa — :id o'zgaruvchi */}
        <Route path="/mahsulot/:id" element={<MahsulotDetali />} />

        {/* 404 — har doim eng oxirida */}
        <Route path="*" element={<TopilmadI />} />
      </Routes>
    </>
  );
}

export default App;
// src/main.jsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import { BrowserRouter } from 'react-router-dom';
import App from './App';

ReactDOM.createRoot(document.getElementById('root')).render(
  <BrowserRouter>
    <App />
  </BrowserRouter>
);
// src/pages/TopilmadI.jsx
import { Link } from 'react-router-dom';

function TopilmadI() {
  return (
    <div>
      <h1>404 — Sahifa topilmadi</h1>
      <p>Bunday sahifa mavjud emas.</p>
      <Link to="/">Bosh sahifaga qaytish</Link>
    </div>
  );
}

export default TopilmadI;

Tez-tez uchraydigan xatolar

1. element ga JSX o'rniga funksiya uzatish

// ❌ Xato — render bo'lmaydi
<Route path="/haqida" element={Haqida} />

// ❌ Xato — v5 usuli
<Route path="/haqida" component={Haqida} />

// ✅ To'g'ri — JSX
<Route path="/haqida" element={<Haqida />} />

Sababi: element prop React elementi (JSX) kutadi, komponent funksiyasini emas. element={Haqida} — bu funksiyaga havola, React uni ko'rsatishni bilmaydi.


2. path="*" ni birinchi qo'yish

// ❌ Xato — * birinchi bo'lsa, hamma URL shu yerga tushadi
<Routes>
  <Route path="*" element={<TopilmadI />} />
  <Route path="/" element={<Bosh />} />
  <Route path="/haqida" element={<Haqida />} />
</Routes>
// ✅ To'g'ri — * har doim eng oxirida
<Routes>
  <Route path="/" element={<Bosh />} />
  <Route path="/haqida" element={<Haqida />} />
  <Route path="*" element={<TopilmadI />} />
</Routes>

Sababi: Routes yuqoridan pastga qaraydi va birinchi mos kelganini oladi. * istalgan URL ga mos keladi — birinchi tursa, boshqa Route larga o'tilmaydi. Har doim eng oxirida bo'lsin.


3. path da bosh slashshiz yozish

// ❌ Xato — slash yo'q
<Route path="haqida" element={<Haqida />} />

// ✅ To'g'ri — slash bilan
<Route path="/haqida" element={<Haqida />} />

Sababi: Bosh / siz path nisbiy yo'l sifatida tushuniladi. Asosiy (top-level) route lar har doim / bilan boshlanishi kerak. Faqat nested route larda (ota Route ichidagi) slash tushirib qoldiriladi.


4. BrowserRouter ni ikki marta o'rash

// main.jsx — BrowserRouter bor
<BrowserRouter>
  <App />
</BrowserRouter>

// App.jsx — yana BrowserRouter — ❌ XATO
function App() {
  return (
    <BrowserRouter>
      <Routes>...</Routes>
    </BrowserRouter>
  );
}

Sababi: Ikki BrowserRouter — ikki mustaqil routing konteksti. Ular bir-biriga zid keladi. React konsolda xato chiqaradi. BrowserRouter faqat bir joyda bo'lsin.


Xulosa

  • BrowserRouter — bir marta, eng tashqarida o'raladi (main.jsx da tavsiya)
  • Routes — barcha Route larni ko'rib chiqib, bitta mosini tanlaydi
  • Route — path + element — qaysi URL da qaysi komponent
  • element={<Komponent />} — JSX ko'rinishida, funksiya sifatida emas
  • path="*" — 404 uchun, har doim eng oxirida
  • v6 da exact kerak emas — avtomatik aniq moslashish
  • Bir nechta Routes bloki mumkin, lekin kamdan-kam kerak bo'ladi

Keyingi dars: 41-dars: Link, NavLink — a tegidan farqi, active holat