Stack navigatsiya — sarlavha, orqaga, push/replace
Muammodan boshlaylik
Katalog → mahsulot → sharhlar → sharh muallifi profili. Foydalanuvchi to'rt qadam chuqur kirdi. "Orqaga" bossa — muallifdan sharhlarga, keyin mahsulotga, keyin katalogga qaytishi kerak. Har bir ekranda sarlavha va orqaga tugmasi bo'lishi kerak; iOS da chap chetdan surib qaytish ishlashi kerak.
Bu — stack (to'plam): ekranlar ustma-ust qo'yiladi, yuqoridagisi ko'rinadi, orqaga — yuqoridagisini olib tashlash.
Stack qanday ishlaydi
push('/mahsulot/5') push('/sharhlar') back()
┌──────────┐ ┌──────────┐ ┌──────────┐
│ │ │ Sharhlar │ ← ko'rinadi│ │
│ Mahsulot │ ← ko'rinadi│ Mahsulot │ │ Mahsulot │ ← ko'rinadi
│ Katalog │ │ Katalog │ │ Katalog │
└──────────┘ └──────────┘ └──────────┘
Pastdagi ekranlar xotirada qoladi — holati, scroll pozitsiyasi saqlangan. Orqaga qaytganda katalog aynan qoldirilgan joyidan davom etadi.
Layout va sarlavhalar
// app/_layout.tsx
import { Stack } from 'expo-router';
export default function RootLayout() {
return (
<Stack
screenOptions={{
headerStyle: { backgroundColor: '#0284c7' },
headerTintColor: 'white', // matn va orqaga tugmasi rangi
headerTitleStyle: { fontWeight: '700' },
headerBackTitle: 'Orqaga', // iOS: orqaga tugmasi yonidagi matn
contentStyle: { backgroundColor: '#f8fafc' },
}}
>
<Stack.Screen name="index" options={{ title: "Do'kon" }} />
<Stack.Screen name="mahsulot/[id]" options={{ title: 'Mahsulot' }} />
<Stack.Screen name="kirish" options={{ headerShown: false }} />
</Stack>
);
}
screenOptions— barcha ekranlar uchunStack.Screen name="..."— aniq bir ekran uchun (fayl nomi bo'yicha). Yozish shart emas — faqat sozlash kerak bo'lsaheaderShown: false— sarlavhasiz ekran (kirish, splash, to'liq ekranli rasm)
Ekranning o'zidan sozlash
Sarlavha ko'pincha ma'lumotga bog'liq — mahsulot nomi serverdan keladi:
// app/mahsulot/[id].tsx
import { Stack, useLocalSearchParams } from 'expo-router';
export default function MahsulotEkran() {
const { id } = useLocalSearchParams<{ id: string }>();
const mahsulot = useMahsulot(id);
return (
<>
<Stack.Screen
options={{
title: mahsulot?.nom ?? 'Yuklanmoqda...',
headerRight: () => (
<Pressable onPress={() => ulashish(mahsulot)} hitSlop={10}>
<Ionicons name="share-outline" size={22} color="white" />
</Pressable>
),
}}
/>
<ScrollView>{/* ... */}</ScrollView>
</>
);
}
<Stack.Screen options> ni ekran ichida render qilish — sarlavhani dinamik o'zgartiradi.
| Option | Ma'nosi |
|---|---|
title |
Sarlavha matni |
headerShown |
Sarlavha ko'rinsinmi |
headerRight / headerLeft |
Sarlavhadagi tugmalar |
headerTransparent |
Shaffof sarlavha (kontent ostiga kiradi) |
headerLargeTitle |
iOS uslubidagi katta sarlavha |
gestureEnabled |
Surib orqaga qaytish |
animation |
slide_from_right, fade, slide_from_bottom, none |
presentation |
card, modal, transparentModal, formSheet (28-dars) |
push, navigate, replace
router.push('/mahsulot/5'); // har doim yangi ekran qo'shadi
router.navigate('/mahsulot/5'); // agar shu ekran stack da bo'lsa — unga qaytadi
router.replace('/bosh'); // joriy ekranni almashtiradi
Qachon replace
Kirish → (muvaffaqiyatli) → Bosh sahifa
push bo'lsa — bosh sahifada "orqaga" bosilganda yana kirish ekrani chiqadi. Noto'g'ri. replace — kirish ekrani stack dan olib tashlanadi.
Xuddi shunday: onboarding → bosh sahifa, to'lov → "rahmat" sahifasi, forma yuborildi → natija.
Stack ni tozalash
router.dismissAll(); // stack ning eng birinchi ekraniga qaytish
router.dismissTo('/katalog'); // aniq ekranga qadar yopish
Buyurtma rasmiylashtirildi → katalogga qaytish, oraliq savat va to'lov ekranlarisiz.
Ekranga qaytganda yangilash
Stack da pastdagi ekran unmount bo'lmaydi — shuning uchun useEffect(..., []) qaytganda qayta ishlamaydi. Profilni tahrirlab qaytdingiz — eski ma'lumot ko'rinadi.
import { useFocusEffect } from 'expo-router';
import { useCallback } from 'react';
useFocusEffect(
useCallback(() => {
profilniYukla(); // ekran har safar ko'ringanda
return () => {
// ekrandan ketganda (masalan, videoni to'xtatish)
};
}, [])
);
useFocusEffect — ekran fokusga kelganda. useCallback — majburiy (har render da qayta ishlamasligi uchun). TanStack Query (32-dars) bu muammoni ko'pincha o'zi hal qiladi.
Orqaga qaytishni boshqarish
Saqlanmagan o'zgarishlar bilan formadan chiqish:
import { useNavigation } from 'expo-router';
const navigation = useNavigation();
useEffect(() => {
if (!ozgargan) return;
const unsub = navigation.addListener('beforeRemove', (e) => {
e.preventDefault();
Alert.alert('Saqlanmagan o\'zgarishlar', 'Chiqib ketsangiz, o\'zgarishlar yo\'qoladi.', [
{ text: 'Qolish', style: 'cancel' },
{ text: 'Chiqish', style: 'destructive', onPress: () => navigation.dispatch(e.data.action) },
]);
});
return unsub;
}, [navigation, ozgargan]);
Orqaga tugmasi, surish va Android "orqaga" — hammasi ushlanadi.
Nima uchun shunday?
Nima uchun stack dagi pastki ekranlar xotirada saqlanadi — o'chirib, qaytganda qayta yaratsa xotira tejalmasmidi?
Chunki foydalanuvchi aynan qoldirgan joyiga qaytishni kutadi. Katalogda 200-mahsulotgacha scroll qildi, birini ochdi, qaytdi — va yana tepadan boshlash kerak bo'lsa, bu juda bezovta. Native ilovalarda (iOS UINavigationController, Android back stack) ham aynan shunday ishlaydi. Xotira odatda muammo emas — stack 3-5 ekrandan chuqur kamdan-kam ketadi. Shu sababli "qaytganda yangilash" uchun maxsus useFocusEffect bor.
Xulosa
Eslab qoling:
- Stack — ekranlar ustma-ust; pastdagilar xotirada, holati saqlanadi
screenOptions— umumiy sozlamalar;<Stack.Screen name>— aniq ekran- Ekran ichida
<Stack.Screen options={{ title }}>— dinamik sarlavha va tugmalar push— qo'shish,navigate— mavjudiga qaytish,replace— almashtirish- Kirish/onboarding/to'lovdan keyin —
replace;dismissAll— boshiga useFocusEffect— ekranga qaytganda yangilashbeforeRemove— saqlanmagan o'zgarishlarda chiqishni tasdiqlash
Keyingi dars
27-dars: Tablar — pastki panel, ikonkalar, badge