Dinamik yo'llar va parametrlar — [id].tsx, deep link

~15 daq · React Native · Navigatsiya — Expo Router

Muammodan boshlaylik

Katalogda 2000 ta mahsulot. Har biri uchun alohida ekran fayli yaratish — imkonsiz. Kerak — bitta "mahsulot ekrani" shabloni, qaysi mahsulotni ko'rsatishni esa parametr belgilaydi: /mahsulot/42, /mahsulot/7.

Va yana: do'stingiz WhatsApp da yuborgan mening-dokon://mahsulot/42 havolasini bosganda — ilova ochilib, aynan shu mahsulot ko'rinishi kerak.


Dinamik segment: [id].tsx

app/
└── mahsulot/
    └── [id].tsx        ← /mahsulot/1, /mahsulot/42, /mahsulot/abc
// app/mahsulot/[id].tsx
import { useLocalSearchParams, Stack } from 'expo-router';
import { View, Text } from 'react-native';

export default function MahsulotEkran() {
  const { id } = useLocalSearchParams<{ id: string }>();

  return (
    <View style={{ flex: 1, padding: 16 }}>
      <Stack.Screen options={{ title: `Mahsulot #${id}` }} />
      <Text>Mahsulot ID: {id}</Text>
    </View>
  );
}
  • Kvadrat qavsdagi nom — parametr nomi: [id] → id
  • useLocalSearchParams — parametrlarni oladi
  • Parametrlar doim string (yoki string massivi). Son kerak bo'lsa — Number(id)

[!WARNING] URL dan kelgan parametr — foydalanuvchi kiritgan ma'lumot kabi: deep link orqali istalgan qiymat kelishi mumkin (/mahsulot/abc, /mahsulot/-1). Tekshiring va "topilmadi" holatini ko'rsating.

O'tish

<Link href={`/mahsulot/${mahsulot.id}`}>...</Link>

// Ob'ekt shaklida — tozaroq, maxsus belgilar avtomatik kodlanadi
<Link href={{ pathname: '/mahsulot/[id]', params: { id: mahsulot.id } }}>...</Link>

router.push({ pathname: '/mahsulot/[id]', params: { id: 42 } });

Query parametrlar

Dinamik segmentdan tashqari qo'shimcha parametrlar:

router.push({ pathname: '/katalog', params: { toifa: 'telefonlar', saralash: 'narx' } });
// → /katalog?toifa=telefonlar&saralash=narx
// app/katalog.tsx
const { toifa, saralash = 'yangi' } = useLocalSearchParams<{ toifa?: string; saralash?: string }>();

Joriy ekran parametrini o'zgartirish (filtr o'zgarganda, yangi ekran ochmasdan):

router.setParams({ saralash: 'narx' });

URL — holatning bir qismi: filtr URL da bo'lsa, uni havola orqali ulashish va deep link bilan ochish mumkin.

Nimani parametrda uzatmaslik kerak

// ❌ Butun ob'ekt
router.push({ pathname: '/mahsulot/[id]', params: { id: 42, mahsulot: JSON.stringify(mahsulot) } });

// ✅ Faqat ID — ma'lumotni ekranning o'zi yuklaydi (yoki keshdan oladi)
router.push({ pathname: '/mahsulot/[id]', params: { id: 42 } });

Sabablari: URL uzunligi cheklangan; deep link bilan kelganda ob'ekt bo'lmaydi; ma'lumot eskirgan bo'lishi mumkin. TanStack Query (32-dars) ro'yxatdagi ma'lumotni keshda saqlaydi — mahsulot ekrani darhol ochiladi.


Boshqa dinamik naqshlar

app/
├── toifa/[toifa]/[id].tsx       ← /toifa/telefonlar/42 → { toifa, id }
├── [...yol].tsx                 ← /a/b/c → { yol: ['a', 'b', 'c'] }
└── foydalanuvchi/[[...tab]].tsx ← /foydalanuvchi va /foydalanuvchi/postlar (ixtiyoriy)

useLocalSearchParams va useGlobalSearchParams farqi: Local — faqat shu ekran fokusda bo'lganda yangilanadi; Global — har qanday URL o'zgarishida. Deyarli doim — Local (ortiqcha qayta chizishdan saqlaydi).


Deep linking

Har bir ekranning URL i bor (25-dars) — demak tashqaridan ochish mumkin.

1. Sxema

// app.json
{ "expo": { "scheme": "mening-dokon" } }

Endi mening-dokon://mahsulot/42 — ilovani ochib, mahsulot ekraniga o'tadi.

2. Sinash

# Android emulyator yoki ulangan telefon
npx uri-scheme open "mening-dokon://mahsulot/42" --android

# iOS simulator
npx uri-scheme open "mening-dokon://mahsulot/42" --ios

Expo Go da sxema boshqacha (exp://...), shuning uchun to'liq sinov — development build da (48-dars).

3. Kodda havola yasash

import * as Linking from 'expo-linking';

const havola = Linking.createURL(`/mahsulot/${id}`);
// development: exp://192.168.1.10:8081/--/mahsulot/42
// production:  mening-dokon://mahsulot/42

Universal links / App Links

mening-dokon:// havolasi faqat ilova o'rnatilgan bo'lsa ishlaydi. Yaxshiroq — oddiy https havola:

https://dokon.uz/mahsulot/42
  • Ilova o'rnatilgan → ilovada ochiladi
  • O'rnatilmagan → saytda ochiladi

Buning uchun saytingizda maxsus fayllar (apple-app-site-association, assetlinks.json) va app.json da associatedDomains (iOS) / intentFilters (Android) sozlanadi. Bu ishlab chiqarish bosqichidagi vazifa — Expo hujjatlarida bosqichma-bosqich.


Push bildirishnomadan ochish

Bildirishnoma ma'lumotida yo'l yuboriladi:

{ "title": "Buyurtmangiz yo'lda", "data": { "url": "/buyurtma/1043" } }

Bosilganda — router.push(data.url). 42-darsda to'liq.


Nima uchun shunday?

Nima uchun parametrlar doim string — id ni son sifatida uzatsam, son bo'lib kelmaydimi?

Chunki parametrlar URL orqali o'tadi, URL esa matn. Deep link, bildirishnoma yoki brauzerdan kelganda hech qanday "tur" haqida ma'lumot yo'q — faqat /mahsulot/42 qatori. Agar ilova ichida o'tganda son, tashqaridan kelganda string bo'lsa — ikki xil xatti-harakat va qiyin topiladigan xatolar. Doim string — doim bir xil: ekran parametrni qanday kelganidan qat'i nazar bir xil yo'l bilan tekshiradi va aylantiradi.


Xulosa

Eslab qoling:

  • [id].tsx — dinamik segment; useLocalSearchParams<{ id: string }>()
  • Parametrlar doim string — Number(id), tekshirish va "topilmadi" holati
  • href={{ pathname: '/mahsulot/[id]', params: { id } }} — ob'ekt shaklida
  • Query parametrlar — filtr va saralash; router.setParams
  • Faqat ID uzating, butun ob'ektni emas
  • [...yol] — qolgan barcha segmentlar
  • Deep link: scheme + Linking.createURL; production — universal / app links

Keyingi dars

30-dars: Autentifikatsiya oqimi — himoyalangan ekranlar