useParams — URL parametrlarni olish

~10 daq · React · Routing

Muammodan boshlaylik

Siz mahsulotlar do'konini yozyapsiz. Har bir mahsulot uchun alohida sahifa bo'lishi kerak: /mahsulot/1, /mahsulot/42, /mahsulot/99.

Agar har bir mahsulot uchun alohida Route yozsangiz:

<Route path="/mahsulot/1" element={<Mahsulot1 />} />
<Route path="/mahsulot/2" element={<Mahsulot2 />} />
<Route path="/mahsulot/3" element={<Mahsulot3 />} />
// ... mingta mahsulot uchun mingta Route?

Bu albatta mumkin emas. Bir bitta Route yozib, ichidagi raqamni dinamik qilib olish kerak:

<Route path="/mahsulot/:id" element={<MahsulotDetali />} />

Endi /mahsulot/1 ham, /mahsulot/999 ham shu Route ga tushadi. Lekin komponent ichida o'sha id ni qanday olamiz?

Buning uchun useParams hook i bor.


useParams nima?

useParams — URL dagi dinamik parametrlarni o'qib beruvchi hook.

Route da :id, :slug, :kategoriya kabi : bilan belgilangan qismlar — dinamik parametrlar. useParams shu parametrlarni ob'ekt ko'rinishida qaytaradi.

Hayotiy o'xshatma: pochta indeksi. Har bir xonadonning o'z indeksi bor — 100001, 100002, 100003. Pochta xizmati bir qoida bilan ishlaydi: "indeksga yetkazib ber". useParams esa joriy xonadonning indeksini aytib beradi.


Asosiy ishlatilish

Route da parametr aniqlanadi:

// App.jsx
<Route path="/mahsulot/:id" element={<MahsulotDetali />} />

Komponent ichida useParams bilan olinadi:

import { useParams } from 'react-router-dom';

function MahsulotDetali() {
  const { id } = useParams(); // ← URL dagi :id ni oladi

  return <h1>Mahsulot raqami: {id}</h1>;
}

/mahsulot/42 da id === "42". /mahsulot/telefon da id === "telefon".


Muhim: parametr har doim string

useParams dan kelgan barcha qiymatlar — string turida. Agar raqam kerak bo'lsa, o'zingiz o'girishingiz kerak:

const { id } = useParams();

// id — "42" (string)
console.log(typeof id); // "string"

// Raqamga o'girish
const raqamliId = Number(id);      // 42
const raqamliId2 = parseInt(id);   // 42
const raqamliId3 = +id;            // 42

Server ga so'rov yuborayotganda ko'pincha raqam kerak bo'ladi:

function MahsulotDetali() {
  const { id } = useParams();

  useEffect(() => {
    mahsulotniOlish(Number(id)); // ← raqamga o'girildi
  }, [id]);
}

Bir nechta parametr

Route da bir nechta dinamik parametr bo'lishi mumkin:

<Route path="/kategoriya/:slug/mahsulot/:id" element={<Detali />} />
function Detali() {
  const { slug, id } = useParams();
  // /kategoriya/telefonlar/mahsulot/42 da:
  // slug === "telefonlar"
  // id   === "42"

  return (
    <div>
      <p>Kategoriya: {slug}</p>
      <p>Mahsulot ID: {id}</p>
    </div>
  );
}

Amaliy misol — server dan ma'lumot olish

import { useParams } from 'react-router-dom';
import { useEffect, useState } from 'react';

function MahsulotDetali() {
  const { id } = useParams();
  const [mahsulot, setMahsulot] = useState(null);
  const [yuklanmoqda, setYuklanmoqda] = useState(true);
  const [xato, setXato] = useState('');

  useEffect(() => {
    setYuklanmoqda(true);

    fetch(`https://api.misol.uz/mahsulotlar/${id}`)
      .then((res) => {
        if (!res.ok) throw new Error('Mahsulot topilmadi');
        return res.json();
      })
      .then((malumot) => {
        setMahsulot(malumot);
        setYuklanmoqda(false);
      })
      .catch((err) => {
        setXato(err.message);
        setYuklanmoqda(false);
      });
  }, [id]); // ← id o'zgarganda qayta so'rov yuboriladi

  if (yuklanmoqda) return <p>Yuklanmoqda...</p>;
  if (xato) return <p>Xato: {xato}</p>;
  if (!mahsulot) return <p>Mahsulot topilmadi</p>;

  return (
    <div>
      <h1>{mahsulot.nomi}</h1>
      <p>{mahsulot.narxi} so'm</p>
      <p>{mahsulot.tavsifi}</p>
    </div>
  );
}

export default MahsulotDetali;

id dependency array da — /mahsulot/42 dan /mahsulot/99 ga o'tganda sahifa qayta yuklanmaydi, lekin useEffect yangi id bilan ishga tushadi va yangi mahsulot yuklanadi.


Ro'yxat + detal sahifa pattern

Keng tarqalgan pattern: ro'yxat sahifasida elementni bossang, detal sahifasiga o'tish.

// App.jsx
<Routes>
  <Route path="/mahsulotlar" element={<Mahsulotlar />} />
  <Route path="/mahsulot/:id" element={<MahsulotDetali />} />
</Routes>
// pages/Mahsulotlar.jsx
import { Link } from 'react-router-dom';

const mahsulotlar = [
  { id: 1, nomi: 'iPhone 15', narxi: 12000000 },
  { id: 2, nomi: 'Samsung S24', narxi: 10000000 },
  { id: 3, nomi: 'Pixel 8', narxi: 9000000 },
];

function Mahsulotlar() {
  return (
    <div>
      <h1>Mahsulotlar</h1>
      {mahsulotlar.map((m) => (
        <div key={m.id}>
          <Link to={`/mahsulot/${m.id}`}>{m.nomi}</Link>
          <span> — {m.narxi.toLocaleString()} so'm</span>
        </div>
      ))}
    </div>
  );
}

export default Mahsulotlar;
// pages/MahsulotDetali.jsx
import { useParams, Link } from 'react-router-dom';

const mahsulotlar = [
  { id: 1, nomi: 'iPhone 15', narxi: 12000000, tavsifi: 'Apple ning yangi modeli' },
  { id: 2, nomi: 'Samsung S24', narxi: 10000000, tavsifi: 'Android ning eng yaxshisi' },
  { id: 3, nomi: 'Pixel 8', narxi: 9000000, tavsifi: "Google ning telefoni" },
];

function MahsulotDetali() {
  const { id } = useParams();
  const mahsulot = mahsulotlar.find((m) => m.id === Number(id)); // ← Number() muhim

  if (!mahsulot) {
    return (
      <div>
        <p>Mahsulot topilmadi</p>
        <Link to="/mahsulotlar">Ro'yxatga qaytish</Link>
      </div>
    );
  }

  return (
    <div>
      <Link to="/mahsulotlar">← Orqaga</Link>
      <h1>{mahsulot.nomi}</h1>
      <p>{mahsulot.narxi.toLocaleString()} so'm</p>
      <p>{mahsulot.tavsifi}</p>
    </div>
  );
}

export default MahsulotDetali;

Tez-tez uchraydigan xatolar

1. Parametrni raqamga o'girmaslik

const { id } = useParams();

// ❌ Xato — string va raqam solishtirilmoqda
const mahsulot = mahsulotlar.find((m) => m.id === id);
// m.id === 42 (number), id === "42" (string) — mos kelmaydi!

// ✅ To'g'ri — Number() bilan o'girish
const mahsulot = mahsulotlar.find((m) => m.id === Number(id));

Sababi: useParams har doim string qaytaradi. Massivdagi id lar raqam bo'lsa, === solishtirish noto'g'ri natija beradi. 42 === "42" — JavaScriptda false.


2. useEffect dependency array dan id ni tushirib qoldirish

// ❌ Xato — id dependency array da yo'q
useEffect(() => {
  mahsulotniYukla(id);
}, []); // ← bo'sh array

// ✅ To'g'ri
useEffect(() => {
  mahsulotniYukla(id);
}, [id]); // ← id o'zgarganda qayta ishlaydi

Sababi: /mahsulot/1 dan /mahsulot/2 ga o'tganda komponent qayta yaratilmaydi — faqat id o'zgaradi. Dependency array da id bo'lmasa, useEffect qayta ishlamaydi — eskicha ma'lumot ko'rinib qoladi.


3. Route da parametr nomini noto'g'ri yozish

// Route da
<Route path="/mahsulot/:mahsulotId" element={<MahsulotDetali />} />

// ❌ Xato — noto'g'ri nom
const { id } = useParams(); // undefined!

// ✅ To'g'ri — Route dagi nom bilan bir xil
const { mahsulotId } = useParams();

Sababi: useParams Route dagi :nom ni kalit sifatida ishlatadi. Nom mos kelmasa — undefined qaytadi.


4. useParams ni Route tashqarisida ishlatish

// ❌ Xato — bu komponent hech qaysi Route da emas
function Sarlavha() {
  const { id } = useParams(); // undefined
  return <h1>Mahsulot {id}</h1>;
}
// ✅ To'g'ri — Route ichida render bo'ladigan komponent yoki uning farzandi
<Route path="/mahsulot/:id" element={<MahsulotDetali />} />

// MahsulotDetali ichida yoki uning farzandida useParams ishlaydi
function MahsulotDetali() {
  return <Sarlavha />; // Sarlavha ham useParams ishlatishi mumkin
}

function Sarlavha() {
  const { id } = useParams(); // ✅ ishlaydi — Route farzandi
  return <h1>Mahsulot {id}</h1>;
}

Sababi: useParams React Router kontekstidan foydalanadi. Bu kontekst faqat BrowserRouter va tegishli Route ichida mavjud.


Xulosa

  • useParams — URL dagi :parametr qiymatlarini olish uchun
  • Barcha qiymatlar string — raqam kerak bo'lsa Number() ishlatish
  • Bir nechta parametr bo'lsa — hammasi ob'ektda qaytadi
  • useEffect dependency array ga id ni qo'shish shart
  • Parametr nomi Route dagi :nom bilan aynan bir xil bo'lishi kerak

Keyingi dars: 44-dars: useSearchParams — query parametrlar bilan ishlash