Offline rejim — tarmoq holati, kesh bilan ishlash

~15 daq · React Native · Ma'lumot va API

Muammodan boshlaylik

Foydalanuvchi metroda ilovani ochdi. Internet yo'q. Ilova:

  • Bo'sh oq ekran va cheksiz spinner
  • Yoki "Network request failed" — qizil yozuv

Lekin u kecha shu katalogni ko'rgan edi! Nima uchun ilova o'sha ma'lumotni ko'rsatmayapti? Va u yozgan izoh — internet qaytganda yuborilishi mumkin edi.

Yaxshi mobil ilova internet bo'lmaganda qisman ishlashda davom etadi. Bu — offline-first yondashuv.


1. Tarmoq holatini bilish

npx expo install @react-native-community/netinfo
import { useNetInfo } from '@react-native-community/netinfo';

export function OfflineBanner() {
  const { isConnected, isInternetReachable } = useNetInfo();
  const offline = isConnected === false || isInternetReachable === false;

  if (!offline) return null;
  return (
    <View style={{ backgroundColor: '#475569', padding: 8 }}>
      <Text style={{ color: 'white', textAlign: 'center', fontSize: 13 }}>
        Internet aloqasi yo'q — saqlangan ma'lumotlar ko'rsatilmoqda
      </Text>
    </View>
  );
}
  • isConnected — Wi-Fi yoki mobil tarmoqqa ulanganmi
  • isInternetReachable — haqiqatan internetga chiqa oladimi (Wi-Fi bor, lekin internet yo'q — kafe Wi-Fi si)
  • Boshida null bo'lishi mumkin — "hali noma'lum"; uni offline deb hisoblamang

2. Ma'lumotni offline ko'rsatish — kesh saqlash

TanStack Query (32-dars) keshni xotirada saqlaydi — ilova yopilsa yo'qoladi. Uni diskka saqlash:

npm install @tanstack/react-query-persist-client @tanstack/query-async-storage-persister
// app/_layout.tsx
import { QueryClient } from '@tanstack/react-query';
import { PersistQueryClientProvider } from '@tanstack/react-query-persist-client';
import { createAsyncStoragePersister } from '@tanstack/query-async-storage-persister';
import AsyncStorage from '@react-native-async-storage/async-storage';

const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      gcTime: 1000 * 60 * 60 * 24,      // 24 soat — keshda saqlash muddati
      staleTime: 60_000,
      networkMode: 'offlineFirst',
    },
  },
});

const persister = createAsyncStoragePersister({ storage: AsyncStorage });

export default function RootLayout() {
  return (
    <PersistQueryClientProvider client={queryClient} persistOptions={{ persister, maxAge: 1000 * 60 * 60 * 24 }}>
      <OfflineBanner />
      <Stack />
    </PersistQueryClientProvider>
  );
}

Endi:

  • Ilova ochildi, internet yo'q → kechagi katalog darhol ko'rinadi
  • Internet qaytdi → onlineManager (32-dars) fonda yangilaydi
  • gcTime — kesh qancha yashashi; persistOptions.maxAge dan kichik bo'lmasin

networkMode: 'offlineFirst' — so'rovni avval sinaydi; tarmoq yo'q bo'lsa — keshdagi ma'lumot bilan ishlaydi va tarmoq qaytishini kutadi (xato bermaydi).


3. Offline yozish — navbat

Foydalanuvchi offline holatda "yoqtirish" ni bosdi yoki izoh yozdi. Variantlar:

A. Mutatsiyalarni to'xtatib turish (TanStack Query)

useMutation({
  mutationKey: ['izoh'],
  mutationFn: (d: { postId: number; matn: string }) => apiPost('/izohlar', d),
  networkMode: 'offlineFirst',
});

Offline bo'lsa — mutatsiya to'xtatiladi (isPaused) va internet qaytganda avtomatik yuboriladi. Persist bilan birga — ilova yopilib ochilsa ham (to'xtatilgan mutatsiyalar uchun setMutationDefaults va resumePausedMutations sozlanadi).

Interfeysda optimistik yangilash (32-dars) — izoh darhol ro'yxatda ko'rinadi, kulrang "yuborilmoqda" belgisi bilan.

B. O'z navbatingiz

Oddiy holatlar uchun — AsyncStorage dagi navbat:

// lib/navbat.ts
type Vazifa = { id: string; yol: string; body: unknown };

export async function navbatgaQosh(v: Omit<Vazifa, 'id'>) {
  const navbat = await xotira.get<Vazifa[]>('navbat', []);
  await xotira.set('navbat', [...navbat, { ...v, id: String(Date.now()) }]);
}

export async function navbatniYubor() {
  const navbat = await xotira.get<Vazifa[]>('navbat', []);
  const qolgan: Vazifa[] = [];
  for (const v of navbat) {
    try {
      await apiPost(v.yol, v.body);
    } catch {
      qolgan.push(v);              // muvaffaqiyatsiz — keyingi safar
    }
  }
  await xotira.set('navbat', qolgan);
}

// Internet qaytganda
NetInfo.addEventListener((s) => { if (s.isConnected) navbatniYubor(); });

[!WARNING] Navbatdagi so'rovlar idempotent bo'lishi kerak: tarmoq uzilsa, so'rov serverga yetib borgan, lekin javob kelmagan bo'lishi mumkin — va u qayta yuboriladi. Har bir vazifaga noyob id bering va server shu id bilan takroriy so'rovni e'tiborsiz qoldirsin (MySQL kursidagi to'lov callback misoli, 60-dars).


4. Qaysi amallar offline ishlashi kerak

Hamma narsani offline qilish shart emas. Savol: "foydalanuvchi internet bo'lmaganda nima qilishni kutadi?"

Amal Offline
Avval ko'rilgan katalog, profil, buyurtmalar ✅ Keshdan ko'rsatish
Eslatma, izoh, "yoqtirish" ✅ Navbatga, keyin yuborish
Savatga qo'shish ✅ Mahalliy (Zustand persist)
To'lov ❌ Faqat onlayn — aniq xabar bilan
Ro'yxatdan o'tish, kirish ❌ Faqat onlayn
Yangi qidiruv ⚠️ Faqat keshdagilar orasida yoki "internet kerak"

Onlayn talab qiladigan amallarda — tugmani o'chirib, sababini ko'rsating:

const { isConnected } = useNetInfo();

<Tugma matn={isConnected === false ? "Internet kerak" : "To'lash"} disabled={isConnected === false} onPress={tolash} />

5. Sinash

  • Telefonda parvoz rejimi — eng oddiy sinov
  • Android emulyator — Extended Controls → Cellular → Network type / Signal
  • iOS — Settings → Developer → Network Link Conditioner ("3G", "Very Bad Network")
  • Sekin internetda sinang — "internet yo'q" dan ko'ra ko'proq uchraydi va ko'proq muammo keltirib chiqaradi

Nima uchun shunday?

Nima uchun offline rejimga bunchalik e'tibor beriladi — hozir hamma joyda internet bor-ku?

"Hamma joyda" — faqat dasturchining ofisida. Haqiqiy foydalanuvchi liftda, metroda, viloyat yo'lida, binoning yerto'lasida, roumingda, oyning oxirida trafik tugaganda. Mobil tarmoq — doim "ba'zan ishlaydi" holatda. Internet uzilganda yiqiladigan ilova — foydalanuvchi uchun "buzilgan" ilova. Offline-first yondashuv esa ilovani tez ham qiladi: kesh darhol ko'rsatiladi, tarmoq faqat fonda yangilaydi.


Xulosa

Eslab qoling:

  • useNetInfo() — isConnected, isInternetReachable; null — noma'lum
  • Offline banner — foydalanuvchiga holatni ayting
  • TanStack Query + persister + AsyncStorage — kesh diskda, ilova offline ochiladi
  • networkMode: 'offlineFirst', gcTime — offline xatti-harakat
  • Offline yozish — to'xtatilgan mutatsiyalar yoki o'z navbatingiz; idempotentlik majburiy
  • To'lov, kirish — faqat onlayn; tugmani o'chirib, sababini ko'rsating
  • Parvoz rejimida va sekin tarmoqda sinang

Keyingi dars

37-dars: 5-6 bo'lim mashqlari — yangiliklar ilovasi