fetch bilan API — yuklanish, xato, bekor qilish

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

Muammodan boshlaylik

Mahsulotlar endi kodda emas — serverda. Ilova ularni internetdan olishi kerak. Lekin mobil tarmoq — vebdan ancha "og'irroq":

  • Metro tunnelida internet yo'qoladi
  • 3G da so'rov 5 soniya davom etadi
  • Foydalanuvchi ekrandan chiqib ketdi, javob esa keyin keldi — va mavjud bo'lmagan ekranni yangilashga urinadi

Har bir so'rov uchun uchta holat kerak: yuklanmoqda, xato, ma'lumot.


fetch asoslari

React Native da fetch — xuddi brauzerdagi kabi:

const javob = await fetch('https://dummyjson.com/products?limit=20');
const data = await javob.json();

POST:

const javob = await fetch('https://api.dokon.uz/buyurtmalar', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    Authorization: `Bearer ${token}`,
  },
  body: JSON.stringify({ mahsulotId: 5, soni: 1 }),
});

[!WARNING] fetch HTTP xato kodlarida (404, 500) xato tashlamaydi — faqat tarmoq uzilganda. javob.ok ni har doim tekshiring.


To'liq naqsh: uchta holat

import { useEffect, useState } from 'react';
import { FlatList, Text, View, ActivityIndicator, Pressable } from 'react-native';

type Mahsulot = { id: number; title: string; price: number; thumbnail: string };

export default function Katalog() {
  const [mahsulotlar, setMahsulotlar] = useState<Mahsulot[]>([]);
  const [yuklanmoqda, setYuklanmoqda] = useState(true);
  const [xato, setXato] = useState<string | null>(null);

  async function yukla(signal?: AbortSignal) {
    setYuklanmoqda(true);
    setXato(null);
    try {
      const javob = await fetch('https://dummyjson.com/products?limit=20', { signal });
      if (!javob.ok) throw new Error(`Server xatosi: ${javob.status}`);
      const data = await javob.json();
      setMahsulotlar(data.products);
    } catch (e) {
      if ((e as Error).name === 'AbortError') return;     // ekrandan chiqildi — e'tiborsiz
      setXato("Ma'lumotni yuklab bo'lmadi. Internet aloqasini tekshiring.");
    } finally {
      setYuklanmoqda(false);
    }
  }

  useEffect(() => {
    const ctrl = new AbortController();
    yukla(ctrl.signal);
    return () => ctrl.abort();          // ekran yopilsa — so'rovni bekor qilish
  }, []);

  if (yuklanmoqda && mahsulotlar.length === 0) {
    return <View style={{ flex: 1, justifyContent: 'center' }}><ActivityIndicator size="large" /></View>;
  }

  if (xato) {
    return (
      <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center', gap: 12, padding: 24 }}>
        <Text style={{ textAlign: 'center' }}>{xato}</Text>
        <Pressable onPress={() => yukla()}><Text style={{ color: '#0284c7', fontWeight: '600' }}>Qayta urinish</Text></Pressable>
      </View>
    );
  }

  return (
    <FlatList
      data={mahsulotlar}
      keyExtractor={(m) => String(m.id)}
      renderItem={({ item }) => <Text style={{ padding: 16 }}>{item.title} — ${item.price}</Text>}
      refreshing={yuklanmoqda}
      onRefresh={() => yukla()}
    />
  );
}

Har bir holat uchun aniq ekran:

  • Yuklanmoqda — spinner (yoki skeleton, 47-dars)
  • Xato — tushunarli xabar va "Qayta urinish" tugmasi. Foydalanuvchini "o'lik" ekranda qoldirmang
  • Ma'lumot — ro'yxat, pull-to-refresh bilan

AbortController

Foydalanuvchi ekranni ochdi va darhol orqaga qaytdi. So'rov hali ketmoqda. Javob kelganda setMahsulotlar — yo'q bo'lgan komponentni yangilashga urinadi. AbortController + cleanup funksiyasi — ekran yopilganda so'rov bekor qilinadi.


API qatlami

Har bir ekranda fetch, headerlar, token, xato tekshiruvi — takrorlanish. Bitta joyga:

// lib/api.ts
import * as SecureStore from 'expo-secure-store';

const BASE_URL = process.env.EXPO_PUBLIC_API_URL ?? 'https://api.dokon.uz';

export class ApiXato extends Error {
  constructor(public status: number, message: string, public data?: unknown) {
    super(message);
  }
}

export async function api<T>(yol: string, options: RequestInit = {}): Promise<T> {
  const token = await SecureStore.getItemAsync('token');

  const javob = await fetch(`${BASE_URL}${yol}`, {
    ...options,
    headers: {
      'Content-Type': 'application/json',
      Accept: 'application/json',
      ...(token ? { Authorization: `Bearer ${token}` } : {}),
      ...options.headers,
    },
  });

  if (javob.status === 204) return undefined as T;

  const data = await javob.json().catch(() => null);

  if (!javob.ok) {
    throw new ApiXato(javob.status, data?.xato ?? `Xato ${javob.status}`, data);
  }
  return data as T;
}

// Qulay yordamchilar
export const apiGet = <T,>(yol: string) => api<T>(yol);
export const apiPost = <T,>(yol: string, body: unknown) =>
  api<T>(yol, { method: 'POST', body: JSON.stringify(body) });

Ishlatish:

const mahsulotlar = await apiGet<Mahsulot[]>('/mahsulotlar?toifa=1');
const buyurtma = await apiPost<{ id: number }>('/buyurtmalar', { mahsulotId: 5, soni: 1 });

Muhit o'zgaruvchilari

# .env
EXPO_PUBLIC_API_URL=https://api.dokon.uz
process.env.EXPO_PUBLIC_API_URL
  • EXPO_PUBLIC_ prefiksi — Expo shu o'zgaruvchilarni ilovaga qo'shadi
  • Maxfiy kalitlarni bu yerga qo'ymang: ilova ichidagi har qanday narsani ochib ko'rish mumkin. Maxfiy kalitlar — faqat serverda

localhost tuzog'i

Kompyuteringizdagi backend http://localhost:3000 da. Telefonda localhost — telefonning o'zi, kompyuter emas.

EXPO_PUBLIC_API_URL=http://192.168.1.10:3000     ← kompyuterning lokal IP si

Android emulyatorda kompyuter — 10.0.2.2. iOS simulatorda localhost ishlaydi. Va Android http:// (shifrlanmagan) so'rovlarni production da bloklaydi — haqiqiy server — faqat https.


Tarmoq holatini tekshirish

npx expo install @react-native-community/netinfo
import NetInfo from '@react-native-community/netinfo';

const holat = await NetInfo.fetch();
if (!holat.isConnected) {
  setXato("Internet aloqasi yo'q");
  return;
}

36-darsda offline rejimni batafsil ko'ramiz.


Nima uchun shunday?

Nima uchun har bir ekranda bunchalik ko'p kod — yuklanish, xato, bekor qilish, qayta urinish?

Chunki mobil tarmoq ishonchsiz — bu istisno emas, odatiy holat. Vebda foydalanuvchi odatda barqaror Wi-Fi da; telefonda esa liftda, metroda, qishloqda. Xato holatini ko'rsatmaydigan ilova — "qotib qolgan" ilova: foydalanuvchi bo'sh ekranga qarab, uni yopadi va o'chirib tashlaydi. Bu kod hajmi — real dunyo murakkabligining aksi. Keyingi darsda TanStack Query bu kodning ko'p qismini o'zi bajaradi.


Xulosa

Eslab qoling:

  • fetch brauzerdagi kabi; javob.ok ni doim tekshiring
  • Uch holat: yuklanmoqda, xato (+ qayta urinish), ma'lumot
  • AbortController + useEffect cleanup — ekran yopilganda bekor qilish
  • API qatlami: bazaviy URL, token, xatolar — bitta api<T>() funksiyada
  • EXPO_PUBLIC_* — muhit o'zgaruvchilari; maxfiy kalitlar ilovada emas
  • Telefonda localhost — telefon; kompyuter IP si yoki 10.0.2.2
  • NetInfo — tarmoq holati

Keyingi dars

32-dars: TanStack Query — kesh, qayta yuklash, mutatsiyalar