18-bo‘lim
Marshrutlash
React Router bilan sahifalar, yo'l parametrlari, ichma-ich marshrutlar va Outlet, dasturiy o'tish hamda so'rov qatori.
Ushbu bo‘lim mundarijasi
React - kutubxona, unda marshrutlash yo'q. Uni alohida qo'shish kerak.
Eng keng tarqalgan yechim - React Router.
npm install react-router
Birinchi marshrutlar #
import { MemoryRouter, Routes, Route } from "react-router";
import { chiz, matn } from "./dom-muhit.mjs";
function Bosh() {
return <h1 id="sahifa">Bosh sahifa</h1>;
}
function Haqida() {
return <h1 id="sahifa">Biz haqimizda</h1>;
}
function Topilmadi() {
return <h1 id="sahifa">404 - topilmadi</h1>;
}
function Ilova({ boshlangichYol }) {
return (
<MemoryRouter initialEntries={[boshlangichYol]}>
<Routes>
<Route path="/" element={<Bosh />} />
<Route path="/haqida" element={<Haqida />} />
<Route path="*" element={<Topilmadi />} />
</Routes>
</MemoryRouter>
);
}
await chiz(<Ilova boshlangichYol="/" />);
console.log(matn("#sahifa"));
await chiz(<Ilova key="2" boshlangichYol="/haqida" />);
console.log(matn("#sahifa"));
await chiz(<Ilova key="3" boshlangichYol="/yoq-bunday" />);
console.log(matn("#sahifa"));
Bosh sahifa
Biz haqimizda
404 - topilmadi
Uch qism:
| Komponent | Vazifasi |
|---|---|
MemoryRouter | Marshrutlash muhitini beradi |
Routes | Mos keladigan bittasini tanlaydi |
Route | Yo'l va komponentni bog'laydi |
path="*" - hech biri mos kelmaganda ishlaydi.
Haqiqiy ilovada BrowserRouter ishlatiladi - u brauzerning
manzil qatori bilan ishlaydi:
import { BrowserRouter } from "react-router";
<BrowserRouter>
<Routes>...</Routes>
</BrowserRouter>
MemoryRouter esa yo'lni xotirada saqlaydi. U ikki joyda
kerak: testlarda va bu darslikdagi kabi misollarda - chunki
haqiqiy manzil qatori bo'lmagan muhitda ham ishlaydi.
19-bo'limda testlarda ham aynan shuni ishlatamiz.
Havolalar #
import { MemoryRouter, Routes, Route, Link } from "react-router";
import { chiz, bos, matn } from "./dom-muhit.mjs";
function Sahifa({ nom }) {
return (
<div>
<h1 id="sahifa">{nom}</h1>
<Link to="/">Bosh</Link>
<Link to="/haqida">Haqida</Link>
</div>
);
}
await chiz(
<MemoryRouter initialEntries={["/"]}>
<Routes>
<Route path="/" element={<Sahifa nom="Bosh sahifa" />} />
<Route path="/haqida" element={<Sahifa nom="Haqida" />} />
</Routes>
</MemoryRouter>,
);
console.log("boshida:", matn("#sahifa"));
const havolalar = [...document.querySelectorAll("a")];
console.log("havola manzillari:",
havolalar.map((h) => h.getAttribute("href")));
await bos("a[href='/haqida']");
console.log("bosilgandan keyin:", matn("#sahifa"));
boshida: Bosh sahifa
havola manzillari: [ '/', '/haqida' ]
bosilgandan keyin: Haqida
<Link to="..."> oddiy <a> ga aylanadi, lekin bosilganda
sahifa qayta yuklanmaydi.
Agar <a href="/haqida"> deb yozsangiz, brauzer butun sahifani
qayta yuklaydi.
Oqibati:
- Butun JavaScript qaytadan yuklanadi - sekin;
- Hamma holat yo'qoladi;
- Ilova qaytadan ishga tushadi.
<Link> esa faqat manzilni o'zgartirib, kerakli komponentni
chizadi. Bu "bir sahifali ilova" (SPA) ning asosiy g'oyasi.
Tashqi saytga havola qilganda esa oddiy <a> to'g'ri - u yerda
haqiqatan sahifa almashishi kerak.
Yo'l parametrlari #
import { MemoryRouter, Routes, Route, useParams } from "react-router";
import { chiz, matn } from "./dom-muhit.mjs";
const kitoblar = {
1: { sarlavha: "O'tkan kunlar", muallif: "Abdulla Qodiriy" },
2: { sarlavha: "Sarob", muallif: "Abdulla Qahhor" },
};
function Kitob() {
const { id } = useParams();
const kitob = kitoblar[id];
if (!kitob) return <p id="natija">Kitob topilmadi: {id}</p>;
return <p id="natija">{kitob.sarlavha} - {kitob.muallif}</p>;
}
function Ilova({ yol }) {
return (
<MemoryRouter initialEntries={[yol]}>
<Routes>
<Route path="/kitoblar/:id" element={<Kitob />} />
</Routes>
</MemoryRouter>
);
}
await chiz(<Ilova yol="/kitoblar/1" />);
console.log(matn("#natija"));
await chiz(<Ilova key="2" yol="/kitoblar/2" />);
console.log(matn("#natija"));
await chiz(<Ilova key="3" yol="/kitoblar/99" />);
console.log(matn("#natija"));
O'tkan kunlar - Abdulla Qodiriy
Sarob - Abdulla Qahhor
Kitob topilmadi: 99
useParams yo'ldagi :id qismini beradi.
Diqqat: qiymat satr bo'ladi - Node.js darsligining
12-bo'limidagi bilan bir xil qoida. Sonli taqqoslash kerak
bo'lsa, Number() bilan aylantiring va tekshiring.
Ichma-ich marshrutlar #
import { MemoryRouter, Routes, Route, Outlet, Link } from "react-router";
import { chiz, matn, html } from "./dom-muhit.mjs";
function Qobiq() {
return (
<div>
<nav id="menyu">
<Link to="/panel">Bosh</Link>
<Link to="/panel/hisobot">Hisobot</Link>
</nav>
<main id="mazmun">
<Outlet />
</main>
</div>
);
}
function PanelBoshi() {
return <p>Panel boshi</p>;
}
function Hisobot() {
return <p>Hisobot sahifasi</p>;
}
function Ilova({ yol }) {
return (
<MemoryRouter initialEntries={[yol]}>
<Routes>
<Route path="/panel" element={<Qobiq />}>
<Route index element={<PanelBoshi />} />
<Route path="hisobot" element={<Hisobot />} />
</Route>
</Routes>
</MemoryRouter>
);
}
await chiz(<Ilova yol="/panel" />);
console.log("menyu bormi:", document.querySelector("#menyu") !== null);
console.log("mazmun:", matn("#mazmun"));
await chiz(<Ilova key="2" yol="/panel/hisobot" />);
console.log("menyu bormi:", document.querySelector("#menyu") !== null);
console.log("mazmun:", matn("#mazmun"));
menyu bormi: true
mazmun: Panel boshi
menyu bormi: true
mazmun: Hisobot sahifasi
Qobiq ikkala sahifada ham qoladi - faqat <Outlet />
ichidagi qism almashadi.
| Yozuv | Ma'nosi |
|---|---|
<Outlet /> | Bola marshrut shu yerga chiziladi |
<Route index> | Ota yo'lining o'zi ochilganda |
path="hisobot" | Nisbiy yo'l: /panel/hisobot |
Ichma-ich marshrutlarsiz har bir sahifada menyuni qayta yozish kerak bo'lardi:
<Route path="/panel" element={<><Menyu /><PanelBoshi /></>} />
<Route path="/panel/hisobot" element={<><Menyu /><Hisobot /></>} />
Bu nafaqat takrorlanish, balki unumdorlik masalasi ham: sahifa almashganda menyu qayta yaratiladi va uning holati - ochiq bo'lim, aylantirish o'rni - yo'qoladi.
Outlet bilan qobiq joyida qoladi.
Dasturiy o'tish #
import { MemoryRouter, Routes, Route, useNavigate } from "react-router";
import { chiz, bos, matn } from "./dom-muhit.mjs";
function Kirish() {
const otish = useNavigate();
function yubor() {
otish("/profil");
}
return (
<div>
<h1 id="sahifa">Kirish</h1>
<button onClick={yubor}>Kirish</button>
</div>
);
}
function Profil() {
const otish = useNavigate();
return (
<div>
<h1 id="sahifa">Profil</h1>
<button onClick={() => otish(-1)}>Orqaga</button>
</div>
);
}
await chiz(
<MemoryRouter initialEntries={["/"]}>
<Routes>
<Route path="/" element={<Kirish />} />
<Route path="/profil" element={<Profil />} />
</Routes>
</MemoryRouter>,
);
console.log(matn("#sahifa"));
await bos("button");
console.log("kirgandan keyin:", matn("#sahifa"));
await bos("button");
console.log("orqaga bosgandan keyin:", matn("#sahifa"));
Kirish
kirgandan keyin: Profil
orqaga bosgandan keyin: Kirish
useNavigate hodisa ichidan sahifa almashtirish imkonini
beradi - masalan, forma muvaffaqiyatli yuborilgandan keyin.
otish(-1) - brauzerdagi "orqaga" tugmasi bilan bir xil.
useNavigate faqat hodisa ichida yoki effektda
chaqirilishi kerak:
function Yomon() {
const otish = useNavigate();
otish("/boshqa"); // XATO: chizish paytida
return <p>...</p>;
}
Bu chizish paytidagi yon ta'sir - React bunga qarshi ogohlantiradi va natija kutilmagan bo'lishi mumkin.
Shart bo'yicha yo'naltirish kerak bo'lsa, <Navigate />
komponentini ishlating:
if (!kirgan) return <Navigate to="/kirish" replace />;
Bu tavsifiy va xavfsiz.
So'rov qatori #
import { MemoryRouter, Routes, Route, useSearchParams } from "react-router";
import { chiz, bos, matn } from "./dom-muhit.mjs";
function Qidiruv() {
const [parametrlar, ozgartir] = useSearchParams();
const so = parametrlar.get("so") ?? "";
const sahifa = Number(parametrlar.get("sahifa") ?? 1);
return (
<div>
<p id="holat">so: "{so}", sahifa: {sahifa}</p>
<button onClick={() => ozgartir({ so: "react", sahifa: "2" })}>
Qidirish
</button>
</div>
);
}
await chiz(
<MemoryRouter initialEntries={["/?so=node&sahifa=3"]}>
<Routes>
<Route path="/" element={<Qidiruv />} />
</Routes>
</MemoryRouter>,
);
console.log(matn("#holat"));
await bos("button");
console.log(matn("#holat"));
so: "node", sahifa: 3
so: "react", sahifa: 2
useSearchParams useState ga o'xshaydi, lekin qiymat
manzilda saqlanadi.
Qidiruv so'zi, filtrlar, sahifa raqami, ochiq bo'lim - bularni
useState da saqlash mumkin, lekin manzilda saqlash yaxshiroq:
- Foydalanuvchi havolani ulashishi mumkin;
- Sahifa yangilanganda holat yo'qolmaydi;
- Brauzerning "orqaga" tugmasi kutilganday ishlaydi;
- Xatcho'p qo'yish ma'noli bo'ladi.
Qoida: holat ko'rinishga tegishli bo'lsa (nima ko'rsatilyapti,
qanday filtrlangan) - manzilga qo'ying. Faqat vaqtinchalik
bo'lsa (ochiq menyu, yozilayotgan matn) - useState da
qoldiring.
Faqat kirganlar uchun #
import { MemoryRouter, Routes, Route, Navigate } from "react-router";
import { chiz, matn } from "./dom-muhit.mjs";
function Himoya({ kirgan, children }) {
if (!kirgan) return <Navigate to="/kirish" replace />;
return children;
}
function Ilova({ kirgan }) {
return (
<MemoryRouter initialEntries={["/profil"]}>
<Routes>
<Route path="/kirish" element={<h1 id="sahifa">Kirish</h1>} />
<Route
path="/profil"
element={
<Himoya kirgan={kirgan}>
<h1 id="sahifa">Profil</h1>
</Himoya>
}
/>
</Routes>
</MemoryRouter>
);
}
await chiz(<Ilova kirgan={false} />);
console.log("kirmagan:", matn("#sahifa"));
await chiz(<Ilova key="2" kirgan={true} />);
console.log("kirgan:", matn("#sahifa"));
kirmagan: Kirish
kirgan: Profil
<Navigate replace /> tarixda yangi yozuv qoldirmaydi - shuning
uchun "orqaga" bosganda foydalanuvchi himoyalangan sahifaga
qaytib tushmaydi.
Yuqoridagi kod interfeys uchun foydali, lekin u xavfsizlik emas.
Hamma React kodi brauzerda ishlaydi - foydalanuvchi uni o'qiy, o'zgartira va chetlab o'ta oladi.
Haqiqiy himoya serverda: har bir so'rovda kim so'rayotgani
tekshiriladi va ruxsat bo'lmasa 401 yoki 403 qaytariladi.
Node.js darsligining 17-bo'limida buni ko'rgansiz.
Mijozdagi tekshiruv faqat qulaylik uchun: foydalanuvchi ko'ra olmaydigan sahifani ochib, bo'sh ekranga qaramasin.
- Uchta marshrut va 404 sahifasini yozing.
Linkbilan sahifalar orasida yuring.- Oddiy
<a>ishlatib, farqni o'ylang. useParamsbilan yo'l parametrini oling.- Mavjud bo'lmagan id uchun xabar chiqaring.
Outletbilan umumiy qobiq yasang.indexmarshrutini qo'shing.useNavigatebilan tugmadan o'ting.useSearchParamsbilan filtrlarni manzilga qo'ying.Navigatebilan himoyalangan marshrut yozing.
Xulosa #
- React da marshrutlash yo'q - React Router qo'shiladi.
Routesmos keladigan bittaRouteni tanlaydi;path="*"- 404.<Link>sahifani qayta yuklamaydi; oddiy<a>yuklaydi.useParamsyo'l qismini beradi va u satr bo'ladi.<Outlet />ichma-ich marshrutlar uchun; qobiq joyida qoladi.useNavigate- hodisa ichidan; chizish paytida<Navigate />.- Ko'rinishga tegishli holatni manzilda saqlang.
- Mijozdagi himoya - xavfsizlik emas; haqiqiy tekshiruv serverda.
Keyingi bo'limda testlarni o'rganamiz.
O‘qish tarixini saqlamoqchimisiz?
Tizimga kirsangiz, tugatgan bo‘limlaringiz saqlanadi va qoldirgan joyingizdan davom etasiz.
Xatolik topdingizmi?
Imlo xatosi, ishlamaydigan kod yoki noto‘g‘ri ma‘lumotni ko‘rsangiz - bizga xabar bering. Har bir xabar administrator tomonidan ko‘rib chiqiladi.