Mundarija (35)
- Bu darsda
- 1. Nega bu kerak?
- 2. useNavigate — koddan o'tish
- 2.1 Amal tugagach — yangi sahifa
- 2.2 Link yoki navigate?
- 2.3 Render paytida emas
- 2.4 Tarix bo'ylab: navigate(-1)
- 3. replace — tarixga qo'shmasdan almashtirish
- 3.1 Tarix — sahifalar to'plami
- 3.2 Render paytida yo'naltirish: <Navigate>
- 4. useLocation — qayerdamiz?
- 4.1 Manzil obyekti
- 4.2 location.state — manzilda ko'rinmaydigan ma'lumot
- 5. useSearchParams — holat URL'da
- 5.1 Filtr useState da bo'lsa
- 5.2 Boshqa parametrlarni saqlash
- 5.3 Qiymat — satr yoki null
- 6. Nisbiy yo'llar
- 6.1 / bilan va / siz
- 6.2 .. va relative="path"
- 7. Vazifalar qadami: aqlli «Orqaga» va kanonik manzil (holat 04)
- 7.1 Nima quramiz
- 7.2 OrqagaTugmasi
- 7.3 Kanonik manzil
- 7.4 Chekka holat: "default" va replace
- 7.5 Tekshiruvlar
- 8. Ko'p uchraydigan xatolar
- 9. Mashqlar
- 1-mashq (oson): tarix qanday bo'ladi?
- 2-mashq (o'rta): tanlangan bo'lim URL'da tursin
- 3-mashq (qiyin): buyurtma oqimi
- 4-mashq: Vazifalar qadami
- 10. Real ishda
- Xulosa
- Manbalar
React Router navigatsiya: useNavigate, replace, useSearchParams, useLocation va nisbiy yo'llar
Qisqacha:
const navigate = useNavigate()— koddan boshqa sahifaga o'tish:navigate("/buyurtma/12"), tarixda orqaga —navigate(-1).{ replace: true }tarixga yangi yozuv qo'shmaydi, joriysini almashtiradi — yo'naltirish va kirishdan keyin shunday. Render paytida yo'naltirish —<Navigate to="…" replace />.useLocation()joriy manzilni beradi:pathname,search,state,key.useSearchParams()—?turi=ichimlikkabi parametrlarni o'qish va yozish: holat URL'da tursa, havola ulashilganda va «Orqaga» bosilganda saqlanadi.
Bu darsda
useNavigatebilan amal tugagach o'tasiz,navigate(-1)bilan orqaga qaytasiz.replaceva<Navigate>bilan tarixni "ifloslantirmasdan" yo'naltirasiz.useLocationvastate,useSearchParamsbilan URL holatini o'qib-yozasiz.- Nisbiy yo'llarni (
"..",relative="path") to'g'ri yozasiz vavazifalarga aqlli «Orqaga» qo'shasiz.
Oldin bilishingiz kerak: React Router II: dinamik, ichma-ich va layout marshrutlar, location va History API, URL va URLSearchParams.
1. Nega bu kerak?
Oldingi darsda «Bahor» saytidagi hamma o'tishlar havola orqali edi. Endi Jasur aka uch narsa so'radi:
- "«Buyurtma berish» bosilsin, buyurtma saqlansin va mehmon o'zi tasdiq sahifasiga o'tsin." Havola yo'q — tugma bor, o'tish saqlashdan keyin.
- "Taom sahifasida «Orqaga» bo'lsin." Qayerga? Menyudan kelgan bo'lsa — menyuga. Telegram'dagi havoladan kirgan bo'lsa — orqada saytimiz yo'q.
- "«Ichimliklar» ni tanlab havolani do'stimga yuborsam, u ham ichimliklarni ko'rsin." Tanlov
useStateda bo'lsa, havolada u yo'q.
Uchalasining javobi — router'ning navigatsiya hook'lari. Hayotiy o'xshatish: taksi. <Link> — yo'lovchi joyni xaritadan o'zi ko'rsatadi. useNavigate — haydovchi buyurtma tugagach o'zi keyingi manzilga yuradi. URL parametrlari — yo'l varaqasi: kim olsa, o'sha yo'nalishni ko'radi.
2. useNavigate — koddan o'tish
2.1 Amal tugagach — yangi sahifa
useNavigate() — funksiya qaytaradigan hook. Shu funksiyaga manzil berasiz, router o'sha sahifaga o'tadi. Odatda u onClick yoki onSubmit ichida, amal tugagandan keyin chaqiriladi.
Natija oynasida manzil satri yo'q — oldingi darslardagidek xotiradagi router va ekranga manzilni yozadigan kichik Address komponenti ishlatamiz. Loyihada — createBrowserRouter, hook'lar bir xil.
import {
createMemoryRouter,
Outlet,
RouterProvider,
useLocation,
useNavigate,
useParams,
} from "react-router";
function Shell() {
const { pathname, search } = useLocation();
return (
<div>
<p>Manzil: {pathname + search}</p>
<Outlet />
</div>
);
}
let lastId = 11;
function Cart() {
const navigate = useNavigate();
function placeOrder() {
lastId += 1; // serverga saqlash o'rnida
navigate(`/buyurtma/${lastId}`);
}
return (
<section>
<p>Savatda: osh, ko'k choy — 40 000 so'm</p>
<button onClick={placeOrder}>Buyurtma berish</button>
</section>
);
}
function Order() {
const { id } = useParams();
return <p>{id}-buyurtma qabul qilindi!</p>;
}
const router = createMemoryRouter([
{
path: "/",
element: <Shell />,
children: [
{ index: true, element: <Cart /> },
{ path: "buyurtma/:id", element: <Order /> },
],
},
]);
export default function App() {
return <RouterProvider router={router} />;
}Ekranda:
Manzil: /buyurtma/12
12-buyurtma qabul qilindi!navigate ga <Link to> dagi narsaning o'zi beriladi — satr manzil. Farqi — qachon: havola — foydalanuvchi bosganda, navigate — kodingiz xohlagan paytda (so'rov tugagach, forma tekshiruvdan o'tgach).
Maslahat: Data router'da
navigate()o'tish tugaganda bajariladigan Promise qaytaradi. Uni kutish shart emas, lekinvazifalardagi ESLint qoidasi "e'tiborsiz qolgan Promise" ni ushlaydi. Shuning uchun kanondavoid navigate("/"):void— "natijasi kerak emas, ataylab".
2.2 Link yoki navigate?
Qaysi birini tanlash — foydalanuvchi uchun muhim:
| Vaziyat | Tanlov | Nega |
|---|---|---|
| foydalanuvchi bossa — o'tadi | <Link> |
haqiqiy <a href>: yangi tabda ochish, nusxalash, ekran o'quvchi "havola" deydi |
| amal tugagach o'tish | navigate |
o'tish natijaga bog'liq (saqlandimi?) |
| render paytida yo'naltirish | <Navigate> |
quyida, «Render paytida yo'naltirish» bo'limida |
Ko'p uchraydigan xato — <button onClick={() => navigate("/menyu")}>. Ishlaydi, lekin yangi tabda ochib bo'lmaydi, Malika (ekran o'quvchi) esa "tugma" eshitadi. Shunchaki boshqa sahifaga olib boradigan narsa — doim <Link>.
2.3 Render paytida emas
navigate ni komponent tanasida — chizish paytida — chaqirib bo'lmaydi. Render "ekranda nima bo'lishini hisoblash", yon ta'sir emas (Pure komponentlar). Sardor "kirmagan bo'lsa — kirish sahifasiga" ni shunday yozdi:
function Cabinet() {
const navigate = useNavigate();
if (!loggedIn) navigate("/kirish"); // ❌ render ichida
return <p>Shaxsiy kabinet</p>;
}Router o'tishni bajarmaydi — ekranda baribir "Shaxsiy kabinet", konsolda esa ogohlantirish:
You should call navigate() in a React.useEffect(), not when your component is first rendered.Tarjimasi: "navigate() ni komponent birinchi chizilayotganda emas, React.useEffect() ichida chaqiring." Bu holat uchun yanada yaxshi yo'l bor — <Navigate>, «Render paytida yo'naltirish» bo'limida.
2.4 Tarix bo'ylab: navigate(-1)
navigate son ham qabul qiladi: -1 — tarixda bir qadam orqaga (brauzerning «Orqaga» tugmasi), 1 — oldinga. Bu History API dagi history.go(-1) ning router versiyasi:
<button onClick={() => navigate(-1)}>Orqaga</button>Jonli ko'rinishi — keyingi bo'limdagi misolda. Nega navigate("/") emas? Menyuda filtr bo'lsa (/?turi=issiq), -1 mehmonni aynan o'sha filtr bilan qaytaradi, brauzer aylantirilgan joyni ham tiklaydi. navigate("/") esa yangi, toza menyuni ochadi — filtr yo'qoladi.
Lekin -1 ning tuzog'i bor. Mehmon /taom/osh ni Telegram'dagi havoladan to'g'ridan ochgan bo'lsa, tarixda saytimizdan oldin — Telegram yoki bo'sh tab. «Orqaga» uni saytdan chiqarib yuboradi. (Natija oynasida buni ko'rmaysiz: xotiradagi tarix birinchi yozuvdan orqaga o'tmaydi.) Davosi — «Vazifalar qadami» da.
Tekshirib ko'ring: Mehmon menyudan «Osh» ga, keyin «Manti» ga havola orqali o'tdi. Manti sahifasida
navigate(-1)chaqirilsa, qayerga tushadi?navigate(-2)chi?
Javob
-1 — osh sahifasiga (tarix: menyu → osh → manti), -2 — menyuga. Raqam — "nechta yozuv orqaga", sahifa nomi emas: foydalanuvchi boshqa yo'l bilan kelsa, -2 boshqa joyga tushiradi. Amalda faqat -1 ishlatiladi.
3. replace — tarixga qo'shmasdan almashtirish
3.1 Tarix — sahifalar to'plami
Brauzer tarixi — ustma-ust qo'yilgan likopchalar kabi. Har yangi sahifa ustiga bitta likopcha qo'shadi (push). «Orqaga» — eng ustkisini oladi. Replace esa ustki likopchani boshqasiga almashtiradi: likopchalar soni o'zgarmaydi.
flowchart LR
subgraph P["navigate('/kabinet')"]
direction TB
P3["/kabinet"] --- P2["/kirish"] --- P1["/"]
end
subgraph R["navigate('/kabinet', replace)"]
direction TB
R2["/kabinet"] --- R1["/"]
endChapda — oddiy o'tish: /kirish tarixda qoldi. O'ngda — replace: /kirish o'rniga /kabinet yozildi. Ikkalasini bitta misolda sinaymiz: kirish sahifasida ikki tugma — «Oddiy kirish» (push) va «replace bilan kirish». Shell har o'tishda manzilni konsolga yozadi:
import { useEffect } from "react";
import {
createMemoryRouter,
Link,
Outlet,
RouterProvider,
useLocation,
useNavigate,
} from "react-router";
function Shell() {
const { pathname } = useLocation();
useEffect(() => console.log("Manzil:", pathname), [pathname]);
return (
<div>
<p>Manzil: {pathname}</p>
<Outlet />
</div>
);
}
function Login() {
const navigate = useNavigate();
return (
<p>
<button onClick={() => navigate("/kabinet")}>
Oddiy kirish
</button>{" "}
<button onClick={() => navigate("/kabinet", { replace: true })}>
replace bilan kirish
</button>
</p>
);
}
function Cabinet() {
const navigate = useNavigate();
return (
<p>
Kabinet <button onClick={() => navigate(-1)}>Orqaga</button>
</p>
);
}
const router = createMemoryRouter([
{
path: "/",
element: <Shell />,
children: [
{ index: true, element: <Link to="/kirish">Kirish</Link> },
{ path: "kirish", element: <Login /> },
{ path: "kabinet", element: <Cabinet /> },
],
},
]);
export default function App() {
return <RouterProvider router={router} />;
}Konsolda:
Manzil: /
Manzil: /kirish
Manzil: /kabinet
Manzil: /kirish
Manzil: /kabinet
Manzil: /Ekranda:
Manzil: /
KirishKonsolni tarix bilan yonma-yon o'qiymiz ([ ] — joriy yozuv):
| Qadam | Tarix | Ekranda |
|---|---|---|
| ochilish | [/] |
Kirish havolasi |
| «Kirish» | /, [/kirish] |
ikki tugma |
| «Oddiy kirish» (push) | /, /kirish, [/kabinet] |
Kabinet |
| «Orqaga» | /, [/kirish], /kabinet |
yana kirish sahifasi |
| «replace bilan kirish» | /, [/kabinet], /kabinet |
Kabinet |
| «Orqaga» | [/], … |
bosh sahifa |
To'rtinchi qator — muammo: foydalanuvchi allaqachon kirgan, «Orqaga» esa uni yana kirish formasiga qaytardi. Haqiqiy ilovada kirish sahifasi "kirgan ekansiz" deb uni yana kabinetga otadi — va «Orqaga» tugmasi "ishlamay" qoladi. replace dan keyin esa /kirish tarixda yo'q: «Orqaga» to'g'ri bosh sahifaga olib keldi. replace qachon kerak? Kirishdan va forma yuborilgandan keyin. Noto'g'ri manzildan to'g'risiga yo'naltirishda. Har harfda URL yangilanadigan qidiruvda.
<Link> da ham shunday: <Link to="/kabinet" replace>.
3.2 Render paytida yo'naltirish: <Navigate>
«Render paytida emas» bo'limidagi muammoga qaytamiz. Chizish paytida "bu sahifa emas, boshqasi" deyish kerak bo'lsa, <Navigate> komponentini qaytaring. U navigate ni o'zi, to'g'ri paytda (chizishdan keyin) chaqiradi:
import {
createMemoryRouter,
Navigate,
RouterProvider,
useParams,
} from "react-router";
function Order() {
const { id } = useParams();
const number = Number(id);
// bitta buyurtma — bitta manzil: /buyurtma/012 → /buyurtma/12
if (Number.isInteger(number) && id !== String(number)) {
return <Navigate to={`/buyurtma/${number}`} replace />;
}
console.log("chizildi:", id);
return <p>{id}-buyurtma</p>;
}
const router = createMemoryRouter(
[{ path: "/buyurtma/:id", element: <Order /> }],
{ initialEntries: ["/buyurtma/012"] },
);
export default function App() {
return <RouterProvider router={router} />;
}Konsolda:
chizildi: 12Ekranda:
12-buyurtmaOldingi darsdagi savol yechildi: /buyurtma/012 va /buyurtma/12 endi bitta sahifa. "012" raqamga aylanganda 12, String(12) esa "12" — teng emas, demak manzil kanonik emas. <Navigate> darhol to'g'risiga o'tkazdi. "012" bilan sahifa umuman chizilmadi — konsolda faqat bitta qator.
Diqqat:
<Navigate>effektda ishlaydi: avval bir kadr chiziladi, keyin o'tish bo'ladi. Ko'pincha bu sezilmaydi. Lekinvazifalarda o'lchandi: kirish sahifasiga<Navigate>bilan yo'naltirilganda birinchi kadr bo'sh edi. Davosi — Himoyalangan marshrutlar darsida.
Tekshirib ko'ring:
<Navigate to="/buyurtma/12" />(replacesiz) bilan/buyurtma/012ochildi. Tarixda nechta yozuv paydo bo'ladi va «Orqaga» nima qiladi?
Javob
Ikkita: /buyurtma/012 va /buyurtma/12. «Orqaga» /buyurtma/012 ga qaytaradi, u yana /buyurtma/12 ga otadi — «Orqaga» go'yo ishlamaydi. Yo'naltirish deyarli doim replace bilan.
4. useLocation — qayerdamiz?
4.1 Manzil obyekti
useLocation() joriy manzilni obyekt qilib qaytaradi. Biz uni darsda Address uchun ishlatdik. To'liq ko'rinishi:
import {
createMemoryRouter,
RouterProvider,
useLocation,
} from "react-router";
function Where() {
const location = useLocation();
console.log(location);
return <p>{location.pathname}</p>;
}
const router = createMemoryRouter(
[{ path: "*", element: <Where /> }],
{ initialEntries: ["/menyu?turi=issiq#manti"] },
);
export default function App() {
return <RouterProvider router={router} />;
}Konsolda:
{pathname: '/menyu', search: '?turi=issiq', hash: '#manti', state: null, key: 'default', mask: undefined}| Maydon | Qiymat | Nima |
|---|---|---|
pathname |
"/menyu" |
yo'l |
search |
"?turi=issiq" |
so'rov qatori (? bilan) |
hash |
"#manti" |
sahifa ichidagi joy |
state |
null |
ko'rinmas ma'lumot (keyingi bo'lim) |
key |
"default" |
shu tarix yozuvining kaliti |
window.location dan farqi — useLocation React'ga ulangan: manzil o'zgarsa, komponent qayta chiziladi (mask bu darsda kerak emas).
key — router har yangi tarix yozuviga beradigan tasodifiy satr ("ht5t5v8l" kabi). Istisno: ilova ochilgan birinchi yozuvning kaliti — "default". Bu «Orqaga» muammosini hal qiladigandek ko'rinadi, lekin replace dan keyin yo'qoladi — «Chekka holat» bo'limida o'lchaymiz.
4.2 location.state — manzilda ko'rinmaydigan ma'lumot
Tasdiq sahifasida buyurtma summasini ko'rsatmoqchimiz. Manzilga yozish (?jami=40000) chiroyli emas, serverdan qayta so'rash — ortiqcha. navigate va <Link> ga state berish mumkin: u tarix yozuvi ichida saqlanadi, manzilda ko'rinmaydi:
import {
createMemoryRouter,
RouterProvider,
useLocation,
useNavigate,
} from "react-router";
function Cart() {
const navigate = useNavigate();
return (
<button
onClick={() =>
navigate("/tasdiq", {
replace: true,
state: { total: "40 000 so'm" },
})
}
>
Buyurtma berish
</button>
);
}
function Thanks() {
const { state } = useLocation();
return (
<p>
Rahmat! Jami: {state?.total ?? "buyurtmalar tarixida ko'ring"}
</p>
);
}
const router = createMemoryRouter([
{ path: "/", element: <Cart /> },
{ path: "/tasdiq", element: <Thanks /> },
]);
export default function App() {
return <RouterProvider router={router} />;
}Ekranda:
Rahmat! Jami: 40 000 so'mstate?.total ?? … qatoriga e'tibor bering — zaxira matni bor. state mo'rt narsa:
| Holat | state saqlanadimi |
|---|---|
| «Orqaga» / «Oldinga» | ha (tarix yozuvi ichida) |
| sahifani yangilash (F5) | ha, brauzerda (history.state) |
| havolani nusxalab yangi tabda ochish | yo'q — manzilda yo'q narsa ko'chmaydi |
| boshqa odamga havola yuborish | yo'q |
Shuning uchun state — faqat qulaylik uchun; sahifa usiz ham ishlashi shart. Muhim ma'lumot — manzilda (:id, ?parametr) yoki serverda. state — sir ham emas: u brauzer tarixida ochiq turadi, har kim o'zgartira oladi. "Admin ekani" yoki narx kabi qarorlarni unga ishonib qabul qilmang. URL'dagi ?keyin= ni tekshirmasdan navigate ga berish xavfi — Himoyalangan marshrutlar darsida.
Tekshirib ko'ring: Mehmon tasdiq sahifasining havolasini nusxalab, do'stiga yubordi. Do'st nimani ko'radi?
Javob
"Rahmat! Jami: buyurtmalar tarixida ko'ring". Do'stning brauzerida bu tarix yozuvi yo'q — u /tasdiq ni yangi ochdi, state — null. state?.total — undefined, ?? zaxira matnni beradi. Zaxira bo'lmaganda state.total ilovani yiqitardi: Cannot read properties of null (reading 'total').
5. useSearchParams — holat URL'da
5.1 Filtr useState da bo'lsa
Menyuda «Issiq taomlar» va «Ichimliklar» tugmalari bor. Tanlov useState da bo'lsa, u faqat shu tabning xotirasida: sahifa yangilansa yoki havola ulashilsa — yo'qoladi.
URL'ning ? dan keyingi qismi — so'rov parametrlari (search params). Ularni URL va URLSearchParams darsida o'qigansiz: ?turi=ichimlik&q=choy. useSearchParams() ularni React'ga ulaydi. U ikki narsa qaytaradi: o'qish uchun URLSearchParams obyekti va yozish funksiyasi — useState dagi juftlik kabi.
import {
createMemoryRouter,
RouterProvider,
useLocation,
useSearchParams,
} from "react-router";
const MENU = [
{ name: "Osh", type: "issiq" },
{ name: "Manti", type: "issiq" },
{ name: "Ko'k choy", type: "ichimlik" },
];
function Menu() {
const { pathname, search } = useLocation();
const [searchParams, setSearchParams] = useSearchParams();
const type = searchParams.get("turi"); // yo'q bo'lsa — null
const dishes =
type === null ? MENU : MENU.filter((d) => d.type === type);
return (
<section>
<p>Manzil: {pathname + search}</p>
<button onClick={() => setSearchParams({})}>
Hammasi
</button>{" "}
<button onClick={() => setSearchParams({ turi: "issiq" })}>
Issiq taomlar
</button>{" "}
<button onClick={() => setSearchParams({ turi: "ichimlik" })}>
Ichimliklar
</button>
<ul>
{dishes.map((d) => (
<li key={d.name}>{d.name}</li>
))}
</ul>
</section>
);
}
const router = createMemoryRouter(
[{ path: "/menyu", element: <Menu /> }],
{ initialEntries: ["/menyu"] },
);
export default function App() {
return <RouterProvider router={router} />;
}Ekranda:
Manzil: /menyu?turi=ichimlik
Hammasi Issiq taomlar Ichimliklar
Ko'k choyuseState yo'q, lekin ro'yxat yangilandi: holatning egasi — URL. setSearchParams manzilni o'zgartiradi, router komponentni qayta chizadi. Endi havolani ulashsa, sahifani yangilasa yoki «Orqaga» bossa — tanlov saqlanadi. setSearchParams ham navigatsiya: tarixga yozuv qo'shadi, ikkinchi argumenti navigate nikiga o'xshaydi ({ replace: true }).
5.2 Boshqa parametrlarni saqlash
setSearchParams({ turi: "issiq" }) butun so'rov qatorini almashtiradi. Manzilda ?q=osh (qidiruv) bor edi deylik — filtr bosilsa, qidiruv yo'qoladi. Birini o'zgartirib, qolganini saqlash uchun funksiya bering. U joriy URLSearchParams ni oladi, siz uni o'zgartirib qaytarasiz:
import {
createMemoryRouter,
RouterProvider,
useLocation,
useSearchParams,
} from "react-router";
function Menu() {
const { search } = useLocation();
const [searchParams, setSearchParams] = useSearchParams();
function setParam(name, value) {
setSearchParams(
(prev) => {
if (value === "") {
prev.delete(name); // bo'sh qiymat URL'da turmasin
} else {
prev.set(name, value);
}
return prev;
},
{ replace: name === "q" }, // har harf — tarixga emas
);
}
return (
<section>
<p>So'rov: {search}</p>
<input
aria-label="Qidiruv"
value={searchParams.get("q") ?? ""}
onChange={(e) => setParam("q", e.target.value)}
/>
<button onClick={() => setParam("turi", "ichimlik")}>
Ichimliklar
</button>
</section>
);
}
const router = createMemoryRouter(
[{ path: "/menyu", element: <Menu /> }],
{ initialEntries: ["/menyu"] },
);
export default function App() {
return <RouterProvider router={router} />;
}Ekranda:
So'rov: ?q=choy&turi=ichimlik
IchimliklarUch odat: funksiya bilan yozish (q saqlandi, turi qo'shildi); bo'sh qiymat — o'chirish (?q= qolmaydi); yozishda replace (aks holda "choy" tarixda to'rt yozuv bo'lardi). Input value si URL'dan o'qiladi — controlled input, faqat state o'rnida URL.
Maslahat: Qachon URL, qachon
useState? Savol: "Bu holat havola bilan birga ketishi kerakmi?" Filtr, saralash, qidiruv, sahifa — URL. Forma qoralamasi, ochiq menyu —useState. Chuqurrog'i — URL — holat saqlash joyi darsida.
5.3 Qiymat — satr yoki null
Parametr — satr, yo'q bo'lsa null (useParams da undefined edi). Son kerak bo'lsa — Number(searchParams.get("sahifa") ?? "1") va tekshiruv: URL'ni har kim o'zgartiradi. ?turi=pitsa kelsa, noma'lum qiymatni "hammasi" deb qabul qiling.
6. Nisbiy yo'llar
6.1 / bilan va / siz
Oldingi darsda havolalarni to'liq yozdik: to={`/taom/${slug}/sharhlar`}. Qisqaroq yo'l ham bor. / bilan boshlanmagan to — nisbiy yo'l, u joriy marshrutga nisbatan hal qilinadi:
to |
/taom/osh marshrutidan |
Ma'nosi |
|---|---|---|
"/menyu" |
/menyu |
mutlaq — ildizdan |
"sharhlar" |
/taom/osh/sharhlar |
shu marshrutning ichiga |
"." |
/taom/osh |
shu marshrutning o'zi |
".." |
ota marshrut | bir qavat yuqoriga |
HTML havolalaridagi nisbiy yo'l kabi (Havola asoslari: ../index.html). Lekin bitta muhim farq bor: .. sukut bo'yicha marshrutlar daraxti bo'yicha yuqoriga chiqadi, URL segmentlari bo'yicha emas.
6.2 .. va relative="path"
Taom tahriri marshruti Shell ning to'g'ridan-to'g'ri bolasi, ichma-ich emas: path: "taom/:slug/tahrir". Tahrir sahifasida ikki «Bekor qilish» havolasi: biri oddiy .., ikkinchisi relative="path" bilan. Qaysi biri qayerga olib borishini havolalarning href i aytadi — Shell ularni har o'tishdan keyin konsolga yozadi:
import { useEffect } from "react";
import {
createMemoryRouter,
Link,
Outlet,
RouterProvider,
useLocation,
} from "react-router";
function Shell() {
const { pathname } = useLocation();
useEffect(() => {
const hrefs = [...document.querySelectorAll("a")].map((a) =>
a.getAttribute("href"),
);
console.log(pathname, "→ havolalar:", hrefs.join(" "));
}, [pathname]);
return (
<div>
<p>Manzil: {pathname}</p>
<Outlet />
</div>
);
}
function Edit() {
return (
<p>
<Link to="..">Daraxt bo'yicha</Link>{" | "}
<Link to=".." relative="path">
URL bo'yicha
</Link>
</p>
);
}
const router = createMemoryRouter(
[
{
path: "/",
element: <Shell />,
children: [
{ index: true, element: <p>Menyu</p> },
{
path: "taom/:slug",
element: <Link to="tahrir">Tahrir</Link>,
},
{ path: "taom/:slug/tahrir", element: <Edit /> },
],
},
],
{ initialEntries: ["/taom/osh"] },
);
export default function App() {
return <RouterProvider router={router} />;
}Konsolda:
/taom/osh → havolalar: /taom/osh/tahrir
/taom/osh/tahrir → havolalar: / /taom/osh
/taom/osh → havolalar: /taom/osh/tahrirEkranda:
Manzil: /taom/osh
TahrirBirinchi qator: <Link to="tahrir"> to'g'ri ishladi — /taom/osh + tahrir. Ikkinchi qator — butun gap. Oddiy .. ning href i — /, ya'ni menyu, taom sahifasi emas. Tahrir marshrutining otasi — Shell (/): daraxtda taom/:slug uning otasi emas. relative="path" bilan .. — URL'dan oxirgi segmentni olib tashlash: /taom/osh/tahrir → /taom/osh. «URL bo'yicha» bosildi va taom sahifasiga qaytdik.
Agar tahrir taom/:slug ning bolasi bo'lganda (oldingi darsdagidek ichma-ich), oddiy .. ham taom sahifasiga olib borardi. Qoida: ichma-ich marshrutda .. tabiiy ishlaydi, yassi marshrutda — relative="path". navigate("..") ham xuddi shunday hal qilinadi, { relative: "path" } bilan.
Nisbiy yo'llarning foydasi: marshrut boshqa joyga ko'chsa (/taom → /menyu/taom), ichidagi havolalar o'zgarmaydi.
Tekshirib ko'ring:
/taom/osh/sharhlarmarshrutitaom/:slugning bolasi (ichma-ich). Undagi<Link to="..">qayerga olib boradi?<Link to="../../menyu">chi?
Javob
.. — ota marshrut taom/:slug, ya'ni /taom/osh. Ichma-ich holatda daraxt va URL mos keladi. ../../menyu — ikki qavat yuqoriga: taom/:slug dan uning otasi / ga, keyin menyu — natija /menyu. Ichma-ich marshrutlarda nisbiy yo'l "papkalar" kabi ishlaydi.
7. Vazifalar qadami: aqlli «Orqaga» va kanonik manzil (holat 04)
7.1 Nima quramiz
Vazifa sahifasidagi <Link to="/">Ro'yxatga qaytish</Link> doim toza ro'yxatga olib boradi: /?filtr=faol&saralash=alifbo dan kelgan foydalanuvchi filtrni ham, saralashni ham yo'qotadi. Uch o'zgarish:
- «Orqaga» tugmasi: ilova ichidan kelingan bo'lsa —
navigate(-1)(filtr bilan), havola bilan to'g'ridan ochilgan bo'lsa —navigate("/"). /vazifa/02→/vazifa/2—<Navigate replace>.- "Ichkaridan kelinganmi?" degan savolga javob — ilova ichidagi tarix chuqurligi:
src/tarix-chuqurligi.ts,src/hooklar/useTarixQadami.tsva ildiz layout'da (Qobiq.tsx) bitta chaqiruv. Nega oddiylocation.keyyetmasligi — «Chekka holat» bo'limida.
git switch -c feat/orqaga7.2 OrqagaTugmasi
Kanondan aynan (izohlar telefonga sig'ishi uchun qayta bo'lingan):
// «Orqaga» (19/#04): ilova ichidan kelingan bo'lsa — tarixda bir
// qadam (ro'yxat filtri, saralashi va aylantirilgan joyi bilan),
// havola bilan to'g'ridan ochilgan bo'lsa — ro'yxatga (aks holda
// Orqaga boshqa saytga chiqib ketardi). Qadam — ilova ichidagi
// tarix chuqurligi (tarix-chuqurligi.ts): 0 — orqada ilovaning
// yozuvi yo'q
function OrqagaTugmasi() {
const navigate = useNavigate();
const { key } = useLocation();
return (
<button
type="button"
id="orqaga"
onClick={() => {
if (joriyQadam(key) === 0) {
void navigate("/");
} else {
void navigate(-1);
}
}}
>
Orqaga
</button>
);
}joriyQadam(key)— shu yozuvdan orqada ilovaning nechta yozuvi bor.0— orqada saytimizdan hech narsa yo'q, demaknavigate("/"). Qadamni kim yozishi va nega u bosilgan paytda o'qilishi — «Chekka holat» bo'limida.navigate(-1)— oldingi sahifa o'z filtri va aylantirilgan joyi bilan.- Nega
<button>,<Link>emas? «Orqaga» ning manzili oldindan noma'lum —hrefga yozadigan aniq manzil yo'q.
7.3 Kanonik manzil
VazifaSahifasi ga qo'shimcha (kanon):
// Bir vazifa — bitta manzil: /vazifa/02 → /vazifa/2. replace
// — tarixga yangi yozuv qo'shilmaydi (Orqaga /vazifa/02 ga
// qaytib, yana shu yerga otib yubormasin)
if (vazifa !== undefined && id !== String(raqam)) {
return <Navigate to={`/vazifa/${raqam}`} replace />;
}«Render paytida yo'naltirish» bo'limidagi misolning o'zi; /vazifa/99 (yo'q vazifa) yo'naltirilmaydi — "Vazifa topilmadi". Pastdagi havola tugmaga almashadi:
<Outlet context={kontekst} />
<p>
- <Link to="/">Ro'yxatga qaytish</Link>
+ <OrqagaTugmasi />
</p>Importlar: Navigate, useLocation, useNavigate va joriyQadam (../tarix-chuqurligi.ts). "Vazifa topilmadi" holatidagi <Link to="/"> o'zgarmaydi.
7.4 Chekka holat: "default" va replace
"Ichkaridan kelinganmi?" degan savolga birinchi xayolga keladigan javob — «Manzil obyekti» bo'limidagi istisno: location.key === "default". Kanonning birinchi varianti shunday edi. Nozik joy: "default" — birinchi yozuvning kaliti, lekin faqat u almashtirilmaguncha. replace yozuvga yangi kalit beradi, tarixda esa o'sha bitta yozuv. Birinchi variantni Chrome 155 da sinadik: yangi tab, manzil, keyin «Orqaga». Nimaga qarash kerak: tugma matnidagi harf (D — kalit "default", B — boshqa) va oxirgi ustun — bosilgandan keyin qayerga tushdik:
/vazifa/2 | tugma: Orqaga D idx=0 | bosilgandan keyin: http://127.0.0.1:59975/
/vazifa/02 | tugma: Orqaga B idx=0 | bosilgandan keyin: about:blankNima bo'ldi? Ikkinchi qatorda foydalanuvchi saytdan chiqib ketdi — bo'sh tabga. /vazifa/02 → /vazifa/2 almashtirildi, kalit endi "default" emas, tugma navigate(-1) ni tanladi. Ehtimoli kichik (kim 02 yozadi?), lekin data mode da almashtirishni loader'dagi replace() ham qiladi. Belgini almashtiramiz.
Tuzatish: chuqurlikni o'zimiz sanaymiz. Aslida savol "bu birinchi yozuvmi?" emas, "orqada ilovaning yozuvi bormi?". Router har o'tishning turini aytadi — useNavigationType(): "PUSH" (yangi yozuv), "REPLACE" (almashtirish) yoki "POP" (brauzerning Orqaga/Oldinga). Kalit bilan birga shu yetarli: har yozuvga qadam yozamiz — ilova ichida undan orqada nechta yozuv bor.
| Tur | Qachon | Yangi yozuvning qadami |
|---|---|---|
| — | ilova ochildi | 0 |
"PUSH" |
havola, navigate("/…") |
oldingisi + 1 |
"REPLACE" |
replace |
oldingisiniki |
"POP" |
brauzerning Orqaga/Oldinga, sahifa yangilandi | yozib qo'yilgani (notanish — 0) |
Natija oynasida — o'sha /vazifa/02:
import { useEffect, useRef } from "react";
import {
createMemoryRouter,
Navigate,
Outlet,
RouterProvider,
useLocation,
useNavigate,
useNavigationType,
useParams,
} from "react-router";
// kalit → qadam (kanonda — sessionStorage'da)
const steps = {};
const stepOf = (key) =>
key !== null && Object.hasOwn(steps, key) ? steps[key] : 0;
// Ildiz layout: har o'tishdan keyin yangi yozuvning qadami
function Root() {
const type = useNavigationType();
const { key } = useLocation();
const prev = useRef(null);
useEffect(() => {
if (prev.current === key) return;
steps[key] =
type === "PUSH"
? stepOf(prev.current) + 1
: type === "REPLACE"
? stepOf(prev.current)
: stepOf(key);
const kind = key === "default" ? "default" : "yangi kalit";
console.log(type, kind, steps[key]);
prev.current = key;
}, [type, key]);
return <Outlet />;
}
function Task() {
const { id } = useParams();
const navigate = useNavigate();
const { key } = useLocation();
const number = Number(id);
if (id !== String(number)) {
return <Navigate to={`/vazifa/${number}`} replace />;
}
return (
<button
onClick={() =>
stepOf(key) === 0 ? navigate("/") : navigate(-1)
}
>
Orqaga
</button>
);
}
const router = createMemoryRouter(
[
{
element: <Root />,
children: [
{ path: "/vazifa/:id", element: <Task /> },
{ path: "/", element: <p>Ro'yxat</p> },
],
},
],
{ initialEntries: ["/vazifa/02"] },
);
export default function App() {
return <RouterProvider router={router} />;
}Konsolda:
POP default 0
REPLACE yangi kalit 0
PUSH yangi kalit 1Ekranda:
Ro'yxatIkkinchi qator — butun gap: kalit endi "default" emas, qadam esa 0. Tugma ro'yxatga o'tdi (PUSH, 1). if (prev.current === key) return — dev rejimidagi StrictMode effektni ikki marta ishga tushiradi, bitta yozuv ikki marta sanalmasin.
Kanonda xarita src/tarix-chuqurligi.ts da, sessionStorage da turadi. Asosiy qismi (kanondan aynan):
function qadam(xarita: TarixXaritasi, kalit: string | null): number {
// hasOwn — "constructor" kabi meros kalitlar qadam bo'lib qolmasin
return kalit !== null && Object.hasOwn(xarita, kalit)
? (xarita[kalit] ?? 0)
: 0;
}
// Yangi yozuvning qadami. PUSH — oldingisidan +1; REPLACE — oldingisi
// (yozuv almashdi, chuqurlik o'sha); POP — Orqaga/Oldinga yoki sahifa
// yangilandi: yozib qo'yilgani. Notanish yozuv, birinchi sahifa — 0
export function qadamHisobi(
xarita: TarixXaritasi,
tur: NavigatsiyaTuri,
oldingi: string | null,
kalit: string,
): number {
if (tur === "PUSH") return qadam(xarita, oldingi) + 1;
if (tur === "REPLACE") return qadam(xarita, oldingi);
return qadam(xarita, kalit);
}
// … xaritaniOqi, xaritaniOl — sessionStorage va xotiradagi nusxa
// Ildiz layout'dan (useTarixQadami) — har navigatsiyadan keyin
export function qadamniYoz(
tur: NavigatsiyaTuri,
oldingi: string | null,
kalit: string,
): void {
const joriy = xaritaniOl();
joriy[kalit] = qadamHisobi(joriy, tur, oldingi, kalit);
try {
sessionStorage.setItem(KALIT, JSON.stringify(joriy));
} catch {
// Yozilmadi (xotira yopiq/to'la) — xotiradagi nusxa yetadi
}
}
// 0 — orqada ilovaning yozuvi yo'q: navigate(-1) saytdan chiqarardi
export function joriyQadam(kalit: string): number {
return qadam(xaritaniOl(), kalit);
}sessionStorage— shu tabniki, sahifa yangilansa ham qoladi: yangilangandan keyin o'tishPOP, kalit o'sha — qadam xaritadan o'qiladi.qadamHisobi— sof funksiya,node:testda 8 ta tekshiruv.xaritaniOqibuzuq JSON va son bo'lmagan qiymatni tashlaydi.- Xotira yopiq bo'lsa — xotiradagi nusxa ishlaydi; eng yomon holatda qadam
0: tugma ro'yxatga olib boradi, saytdan chiqarmaydi.
Ildiz layout uchun hook (src/hooklar/useTarixQadami.ts, kanondan aynan):
// useTarixQadami.ts — ildiz layout'da (Qobiq, 19/#04): har
// navigatsiyada yozuvning qadamini yozadi (tarix-chuqurligi.ts).
// Faqat hujjatlangan API: navigatsiya turi (PUSH/REPLACE/POP) va
// location.key. Effekt — chizilgandan keyin; «Orqaga» qadamni
// bosilganda o'qiydi, u paytda yozib bo'lingan
import { useEffect, useRef } from "react";
import { useLocation, useNavigationType } from "react-router";
import { qadamniYoz } from "../tarix-chuqurligi.ts";
export function useTarixQadami(): void {
const tur = useNavigationType();
const { key } = useLocation();
const oldingi = useRef<string | null>(null);
useEffect(() => {
// StrictMode effektni ikki marta ishlatadi — bir marta sanalsin
if (oldingi.current === key) return;
qadamniYoz(tur, oldingi.current, key);
oldingi.current = key;
}, [tur, key]);
}Qobiq.tsx da — useTarixQadami();. Nega ildiz layout'da? Qobiq hamma sahifada turadi va qayta o'rnatilmaydi — ro'yxatdagi o'tishlar ham sanaladi. VazifaSahifasi.tsx da — bitta shart:
- if (key === "default") {
+ if (joriyQadam(key) === 0) {Qadam bosilganda o'qiladi, render paytida emas: effekt chizilgandan keyin ishlaydi, birinchi chizishda qadam hali yozilmagan (render paytida o'qilgani hamma joyda 0 edi). Tuzatilgan mantiq Chrome 155 da — qarang, «bosilganda qadam» va oxirgi ustunga:
to'g'ridan /vazifa/02 (→ /vazifa/2) | tugma: Orqaga B, bosilganda qadam=0 → navigate("/", replace) | bosilgandan keyin: /
ro'yxat → havola /vazifa/02 (→ /vazifa/2) | tugma: Orqaga B, bosilganda qadam=1 → navigate(-1) | bosilgandan keyin: /Birinchi qator — avval bo'sh tabga chiqargan holat, endi ro'yxat. Ikkinchisida replace dan keyin ham qadam 1: ro'yxat o'z filtri bilan qaytadi. (O'lchovda zaxira { replace: true } bilan — kanon keyinroq shunday qiladi.)
Nega history.state.idx emas? Router brauzer tarixiga { usr, key, idx } yozadi, idx — aynan chuqurlik. Lekin u hujjatlarda yo'q — router'ning ichki ishi: keyingi versiyada o'zgarsa, na TypeScript, na testlar ogohlantiradi. history.length ham yaramaydi: boshqa saytlarning yozuvlarini ham sanaydi. Bizning kod faqat hujjatlangan ikki qiymatga (tur va kalit) tayanadi.
7.5 Tekshiruvlar
git add -A
git commitCommit (kanon): feat: vazifa sahifasida «Orqaga» — tarix yoki ro'yxat; /vazifa/02 → /vazifa/2.
Tekshiruvlar (haqiqiy, holat 04):
npm test— node:test 182 (174 + 8 —tekshiruv/tarix-chuqurligi.test.js), Vitest 49.lint,format:check,tip,knip—exit 0. Build:gzip: 114.25 kB(oldin 113.68, +0.6 KB).- Brauzer: 159/159, 72/72, 19-qism — 32/32. Yangi oltitasi:
✅ Orqaga: ro'yxatdan kelingan — o'sha filtr va saralash bilan: ["/?filtr=faol&saralash=alifbo",["3","1"]]
✅ Orqaga: havola bilan to'g'ridan ochilgan — ro'yxatga: ["/",1]
✅ Navigate replace: /vazifa/02 → /vazifa/2, tarix o'smadi: ["/vazifa/2",0,"Sut olish #bozor"]
✅ navigatsiya: CSP buzilishi yo'q: []
✅ Orqaga: /vazifa/02 yangi tabda (replace) — ilovada, ro'yxatda: ["/",true]
✅ Orqaga: ro'yxatdan kelib, sahifa yangilangach — o'sha filtr bilan: "/?filtr=faol"Birinchi qator — filtr va saralash bilan qaytish. Uchinchisi — /vazifa/02 → /vazifa/2, tarix o'smadi (0). Beshinchisi — chekka holat: tuzatishdan oldingi kod bilan shu tekshiruv ["about:blank",false] bergan edi. Oltinchisi — sahifa yangilangandan keyin ham qadam sessionStorage da. Diff: 5 fayl, +250 −2 (test bilan).
Maslahat: Ro'yxat filtri hozircha 17-qismdagi o'z
pushStatekodimiz bilan yoziladi — URL — holat saqlash joyi darsida u router tarixini qanday buzishini o'lchab,useSearchParamsga ko'chiramiz.
8. Ko'p uchraydigan xatolar
| Belgi | Sabab | Davosi |
|---|---|---|
You should call navigate() in a React.useEffect(), not when your component is first rendered. |
navigate render ichida |
<Navigate to replace /> qaytaring yoki hodisada chaqiring |
| «Orqaga» saytdan chiqarib yuboradi | sahifa havola bilan ochilgan, navigate(-1) |
ilova ichidagi qadam 0 — navigate("/") |
/vazifa/02 dan «Orqaga» — bo'sh tab |
replace yangi kalit berdi, "default" yo'qoldi |
chuqurlikni sanash (useNavigationType + key) |
| «Orqaga» ishlamaydi, sahifa joyida qoladi | yo'naltirish replace siz |
<Navigate replace> yoki { replace: true } |
| filtr bosilsa, qidiruv yo'qoladi | setSearchParams({ … }) hammasini almashtiradi |
funksiya bilan: prev.set(…) |
| qidiruvda har harf — alohida «Orqaga» | yozish replace siz |
setSearchParams(…, { replace: true }) |
state.total — Cannot read properties of null |
sahifa yangi tabda ochilgan | state?.total ?? zaxira |
.. boshqa sahifaga olib boradi |
marshrut yassi, .. daraxt bo'yicha |
relative="path" yoki ichma-ich marshrut |
searchParams.get("sahifa") + 1 → "21" |
qiymat — satr | Number(…) va tekshiruv |
9. Mashqlar
Mashqlar kurs/mashqlar/19/04-navigatsiya/ da. Har yechimni «Ishga tushir» bilan sinang.
1-mashq (oson): tarix qanday bo'ladi?
Mehmon menyu sahifasida (/). Tarixda bitta yozuv: [/]. U ketma-ket quyidagilarni qiladi. Har qadamdan keyin joriy manzilni yozing:
<Link to="/taom/osh">ni bosdi →navigate("/savat")→navigate("/tasdiq", { replace: true })→navigate(-1)→
Yechim
Tarix har qadamda:
| Qadam | Tarix | Joriy |
|---|---|---|
| 1 | /, /taom/osh |
/taom/osh |
| 2 | /, /taom/osh, /savat |
/savat |
| 3 | /, /taom/osh, /tasdiq |
/tasdiq |
| 4 | o'sha | /taom/osh |
Uchinchi qadam /savat ni /tasdiq ga almashtirdi — shuning uchun -1 osh sahifasiga qaytardi. Buyurtma berilgan savatga qaytish ma'nosiz.
2-mashq (o'rta): tanlangan bo'lim URL'da tursin
Quyidagi menyuda bo'lim useState da. Uni useSearchParams ga o'tkazing:
- Tanlangan bo'lim —
?bolim=…parametrida (salatyokishirinlik). - Parametr yo'q yoki noma'lum bo'lsa —
salat. - Tugma bosilsa —
setSearchParamsbilan.
Ishora: «Filtr useState da bo'lsa» bo'limidagi misol. useLocation bilan manzilni ekranga yozing.
import { useState } from "react";
import { createMemoryRouter, RouterProvider } from "react-router";
const ITEMS = {
salat: "Achchiq-chuchuk, Vinegret",
shirinlik: "Chak-chak, Navvot",
};
function Menu() {
const [section, setSection] = useState("salat");
return (
<section>
<button onClick={() => setSection("salat")}>
Salatlar
</button>{" "}
<button onClick={() => setSection("shirinlik")}>
Shirinliklar
</button>
<p>{ITEMS[section]}</p>
</section>
);
}
const router = createMemoryRouter(
[{ path: "/menyu", element: <Menu /> }],
{ initialEntries: ["/menyu"] },
);
export default function App() {
return <RouterProvider router={router} />;
}Ekranda:
Salatlar Shirinliklar
Chak-chak, NavvotYechim
import {
createMemoryRouter,
RouterProvider,
useLocation,
useSearchParams,
} from "react-router";
const ITEMS = {
salat: "Achchiq-chuchuk, Vinegret",
shirinlik: "Chak-chak, Navvot",
};
function Menu() {
const { pathname, search } = useLocation();
const [searchParams, setSearchParams] = useSearchParams();
const asked = searchParams.get("bolim");
const section = asked !== null && asked in ITEMS ? asked : "salat";
return (
<section>
<p>Manzil: {pathname + search}</p>
<button onClick={() => setSearchParams({ bolim: "salat" })}>
Salatlar
</button>{" "}
<button onClick={() => setSearchParams({ bolim: "shirinlik" })}>
Shirinliklar
</button>
<p>{ITEMS[section]}</p>
</section>
);
}
const router = createMemoryRouter(
[{ path: "/menyu", element: <Menu /> }],
{ initialEntries: ["/menyu?bolim=pitsa"] },
);
export default function App() {
return <RouterProvider router={router} />;
}Ekranda:
Manzil: /menyu?bolim=shirinlik
Salatlar Shirinliklar
Chak-chak, NavvotuseState ketdi — holatning yagona manbai URL. Ataylab noma'lum ?bolim=pitsa bilan ochildi: ekranda salatlar, ilova yiqilmadi. asked in ITEMS meros kalitlarni ham ko'radi ("toString" in ITEMS — true); qat'iyroq — Object.hasOwn(ITEMS, asked).
3-mashq (qiyin): buyurtma oqimi
Ikki sahifali oqim yasang:
/—Cart:<p>Savat: 2 ta osh</p>va «Tasdiqlash» tugmasi. Bosilsa —/tasdiqga,replacebilan,stateda{ count: 2 }./tasdiq—Confirm:<p>Qabul qilindi: 2 ta</p>(sonstatedan) va «Yangi buyurtma» havolasi (/ga).statebo'lmasa (tasdiq sahifasi to'g'ridan ochilgan) —<Navigate to="/" replace />.
Ishora: «location.state» va «Render paytida yo'naltirish» bo'limlari. Router initialEntries: ["/tasdiq"] bilan boshlansin — tasdiq sahifasi to'g'ridan ochilgan holat: u savatga yo'naltirilishi kerak.
Yechim
import {
createMemoryRouter,
Link,
Navigate,
RouterProvider,
useLocation,
useNavigate,
} from "react-router";
function Cart() {
const navigate = useNavigate();
return (
<section>
<p>Savat: 2 ta osh</p>
<button
onClick={() =>
navigate("/tasdiq", { replace: true, state: { count: 2 } })
}
>
Tasdiqlash
</button>
</section>
);
}
function Confirm() {
const { state } = useLocation();
if (state === null) {
return <Navigate to="/" replace />;
}
return (
<section>
<p>Qabul qilindi: {state.count} ta</p>
<Link to="/">Yangi buyurtma</Link>
</section>
);
}
const router = createMemoryRouter(
[
{ path: "/", element: <Cart /> },
{ path: "/tasdiq", element: <Confirm /> },
],
{ initialEntries: ["/tasdiq"] },
);
export default function App() {
return <RouterProvider router={router} />;
}Ekranda:
Qabul qilindi: 2 ta
Yangi buyurtmaQadamma-qadam:
| Qadam | Tarix | Ekranda |
|---|---|---|
ochilish: /tasdiq, state — null |
<Navigate replace> → [/] |
savat |
| «Tasdiqlash» | / almashtirildi → [/tasdiq] |
Qabul qilindi: 2 ta |
Tarixda butun oqim davomida bitta yozuv: ikkala o'tish ham replace. Tasdiq sahifasidan «Orqaga» savatga qaytarmaydi — buyurtmani qayta yuborish xavfi yo'q. state.count ga ?. kerak emas: null holati yuqorida ajratilgan. Bu yerda location.key === "default" ga tayangan «Orqaga» xato qilardi — ikki replace dan keyin kalit "default" emas («Chekka holat»).
4-mashq: Vazifalar qadami
feat/orqaga branch'ida «Vazifalar qadami» bo'limidagi uch o'zgarishni qiling: tarix-chuqurligi.ts va useTarixQadami (testi bilan), Qobiq.tsx da chaqiruv, VazifaSahifasi.tsx da OrqagaTugmasi va kanonik manzil yo'naltirishi. Keyin commit.
Yechim
Tekshiruv ro'yxati (npm run dev):
- «Faol» + alifbo saralashi → «Batafsil» → «Orqaga»: manzilda
?filtr=faol&saralash=alifbo. - Yangi tabda
/vazifa/2(va/vazifa/02) → «Orqaga»: ro'yxat, saytdan chiqmaysiz. - Ro'yxatdan vazifaga, F5, «Orqaga» — ro'yxat, filtri bilan.
/vazifa/02→/vazifa/2;/vazifa/99— "Vazifa topilmadi".npm test— node 182, Vitest 49.
10. Real ishda
- Kirish oqimlari —
navigate(…, { replace: true })va?keyin=deyarli har SPA'da bor. - Internet-do'kon filtrlari —
?narx=0-100000&rang=qizil&sahifa=2: filtr havolasini ulashsa bo'ladi (URL — holat saqlash joyi). - Next.js —
useRouter().push/replace/backvauseSearchParams(Navigatsiya: Link, useRouter va URL hooklari): g'oyalar o'sha. - Analitika — SPA'da sahifa ko'rishi
useLocationo'zgarishidan sanaladi. - Intervyu savollari: "
LinkvauseNavigatefarqi?", "replaceqachon kerak?", "location.statenima va qachon yo'qoladi?", "filtrni qayerda saqlaysiz — state yoki URL?".
Xulosa
useNavigate()— koddan o'tish, amal tugagach; bosib o'tiladigan joy —<Link>; render ichida —<Navigate>.navigate(-1)— orqaga, filtr bilan. Orqada ilovaning yozuvi yo'q bo'lsa —navigate("/"); buni"default"kalit emas, o'zimiz sanagan chuqurlik aytadi.replace— joriy yozuvni almashtiradi: kirishdan keyin, yo'naltirishda, qidiruvda.useLocation()—pathname,search,hash,state,key;stateyangi tabda yo'qoladi va sir emas.useSearchParams()— holat URL'da; qiymat satr yokinull; boshqa parametrlarni saqlash — funksiya bilan.- Nisbiy yo'l — marshrut daraxti bo'yicha; URL bo'yicha —
relative="path".
Keyingi dars: React Router IV: data mode — loader, action va xatolar — ma'lumotni sahifa chizilishidan oldin loader da yuklash, formani action ga yuborish va xatoni errorElement da ushlash.
Manbalar
- React Router: Navigating — reactrouter.com/start/data/navigating (2026-10 holatiga, v8.4.0)
- React Router:
useNavigate,Navigate,useLocation,useNavigationType,useSearchParams— reactrouter.com/api/hooks/…, /api/components/Navigate - React Router:
Link(relative,replace,state) — reactrouter.com/api/components/Link - MDN:
History.state,History.length,Window.sessionStorage,URLSearchParams— developer.mozilla.org
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!