Stack navigatsiya — sarlavha, orqaga, push/replace

~15 daq · React Native · Navigatsiya — Expo Router

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 uchun
  • Stack.Screen name="..." — aniq bir ekran uchun (fayl nomi bo'yicha). Yozish shart emas — faqat sozlash kerak bo'lsa
  • headerShown: 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 yangilash
  • beforeRemove — saqlanmagan o'zgarishlarda chiqishni tasdiqlash

Keyingi dars

27-dars: Tablar — pastki panel, ikonkalar, badge