17 β Tarmoq va API¶
β¬ οΈ Oldingi: 16 β Dinamik marshrut va parametrlar Β· π Kitob boshi Β· Keyingi: 18 β Lokal saqlash β‘οΈ
Bu bobda: Ilovangizni internetga ulaymiz. API nimaligini,
fetchbilan serverdan ma'lumot olishni, loading / error / data uch holatini to'g'ri boshqarishni o'rganamiz. POST/PUT/DELETE bilan ma'lumot yuborishni,axiosalternativasini, xatolarni chiroyli ishlashni, qayta ishlatiladiganuseFetchhookini va so'rovni bekor qilishni (AbortController) ko'rib chiqamiz. Oxirida real API'dan postlar ro'yxatini yuklaydigan to'liq ilova quramiz.
Nega ilovaga internet kerak?¶
Hozirgacha biz qurgan ilovalar faqat o'z ichidagi ma'lumot bilan ishlaydi: siz yozgan ro'yxat, hisoblagich soni, forma qiymatlari. Lekin haqiqiy ilovalar deyarli har doim tashqi dunyo bilan gaplashadi:
- Instagram boshqalar yuklagan rasmlarni ko'rsatadi,
- ob-havo ilovasi bugungi haroratni serverdan oladi,
- onlayn do'kon mahsulotlar ro'yxatini yuklaydi,
- chat ilovasi yangi xabarlarni qabul qiladi.
Bu ma'lumotlarning hammasi sizning telefoningizda emas, balki internetdagi serverda turadi. Ilova serverga "menga postlar ro'yxatini ber" deb murojaat qiladi, server javob qaytaradi, ilova esa uni ekranga chizadi. Mana shu muloqotni o'rganamiz.
Hayotiy o'xshatish. API bilan ishlashni restoranda ovqatlanishga o'xshating. Siz (ilova) ofitsiantga buyurtma berasiz β bu so'rov (request). Keyin biroz kutasiz β oshxona (server) taom tayyorlaydi. So'ng ofitsiant taomingizni keltiradi β bu javob (response). Siz oshxonaga kirib ovqat pishirmaysiz; faqat menyu orqali so'raysiz. Aynan shunday, ilova ham serverning ichki ishlashini bilmaydi β u faqat to'g'ri so'rov yuborib, javobni kutadi.
API va REST nima?¶
API (Application Programming Interface β "dasturlar o'rtasidagi muloqot interfeysi") β bu ikki dastur bir-biri bilan qanday gaplashishini belgilaydigan qoidalar to'plami. Restoran menyusi kabi: menyu sizga nima so'rash mumkinligini va qanday so'rashni ko'rsatadi.
Bugungi kunda eng keng tarqalgan API turi β REST API. Uning asosiy g'oyasi sodda:
- Har bir ma'lumot turi o'z manzili (URL) ga ega. Masalan,
https://api.example.com/postsβ postlar,https://api.example.com/usersβ foydalanuvchilar. - Siz bu manzilga HTTP metodi bilan murojaat qilasiz: olish uchun
GET, qo'shish uchunPOSTva hokazo (buni quyida ko'ramiz). - Server ko'pincha JSON formatida javob qaytaradi.
Eslatma. JSON (JavaScript Object Notation) β bu ma'lumotni matn ko'rinishida yozish formati. U JavaScript obyektiga juda o'xshaydi va inson ham, kompyuter ham osongina o'qiy oladi. Masalan, bitta post quyidagicha ko'rinadi:
Biz bu bobda JSONPlaceholder (https://jsonplaceholder.typicode.com) nomli bepul, ro'yxatdan o'tishsiz ishlaydigan test API'sidan foydalanamiz. U haqiqiy postlar, foydalanuvchilar va izohlarni qaytaradi β mashq qilish uchun ideal.
fetch β birinchi so'rov¶
React Native'da serverga so'rov yuborishning eng oddiy yo'li β fetch funksiyasi. U ilovaga allaqachon o'rnatilgan; hech narsa qo'shish shart emas (xuddi brauzerdagi kabi).
fetch asinxron (asynchronous) ishlaydi β ya'ni javob darrov kelmaydi, internetdan ma'lumot kelishini biroz kutish kerak. Shu sababli biz async/await ishlatamiz.
Hayotiy o'xshatish. "Asinxron" so'zidan qo'rqmang. Bu shunchaki "darhol emas, biroz kutib" degani. Choy damlashga o'xshaydi: choynakka suv quyib, qaynashini kutasiz β shu vaqt davomida boshqa ish bilan shug'ullanishingiz mumkin.
awaitso'zi esa "men shu joyda natija kelguncha kutaman" deydi.
Eng sodda GET so'rovi ikki qadamdan iborat:
// 1-qadam: serverga murojaat qilamiz va javobni kutamiz
const javob = await fetch('https://jsonplaceholder.typicode.com/posts');
// 2-qadam: javobni JSON'ga aylantiramiz (yana kutamiz)
const data = await javob.json();
console.log(data); // postlar massivi
Diqqat qiling: bu yerda ikkita await bor. Birinchisi β serverdan javob kelishini kutadi. Ikkinchisi β kelgan javobni JavaScript obyektiga aylantirishni kutadi (javob.json() ham asinxron). Bu juda keng uchraydigan ikki qadam, uni yodda saqlang.
Eslatma.
awaitfaqatasyncfunksiya ichida ishlatiladi. Shuning uchun ko'pinchafetchni alohidaasyncfunksiyaga o'rab qo'yamiz, masalanasync function postlarniYukla() { ... }.
async/awaitning eski muqobili β .then() zanjiri. Ba'zi kodlarda uchratasiz, shuning uchun ko'rib qo'ying:
fetch('https://jsonplaceholder.typicode.com/posts')
.then((javob) => javob.json()) // javobni JSON'ga aylantir
.then((data) => console.log(data)) // natijani ishlat
.catch((xato) => console.log(xato)); // xato bo'lsa ushla
Ikkalasi ham bir xil ishni qiladi. Biz kitobda asosan async/awaitdan foydalanamiz β u ko'proq o'qishga oson.
Uch holat β eng muhim tushuncha¶
Bu bobdagi eng muhim g'oyaga keldik. Har qanday tarmoq so'rovi uchta holatdan o'tadi va siz har birini foydalanuvchiga ko'rsatishingiz kerak:
- Loading (yuklanmoqda) β so'rov yuborildi, javob hali kelmadi. Foydalanuvchiga aylanuvchi spinner ko'rsatamiz.
- Error (xato) β biror narsa noto'g'ri ketdi (internet yo'q, server ishlamadi). Tushunarli xato xabarini ko'rsatamiz.
- Data (ma'lumot) β javob muvaffaqiyatli keldi. Endi ma'lumotni ekranga chizamiz.
Hayotiy o'xshatish. Tasavvur qiling, pizza buyurtma qildingiz. Uch holat bor: kutyapsiz ("yetkazib berilmoqda" β loading), muammo ("kuryer adashdi" β error), yoki pizza keldi (data). Yaxshi ilova hech qachon sizni qorong'uda qoldirmaydi β har doim qaysi holatda ekanligini bildiradi.
Ko'pchilik boshlovchilar faqat "data" holatini ko'rsatadi va loading/error'ni unutadi. Natijada foydalanuvchi bo'sh ekranga qarab "ilova qotdimi?" deb o'ylaydi. Shuning uchun uch holatni har doim birga boshqaring. Buning uchun uchta useState ishlatamiz:
import { useState } from 'react';
const [data, setData] = useState(null); // ma'lumot (boshda yo'q)
const [yuklanmoqda, setYuklanmoqda] = useState(true); // boshda yuklanmoqda
const [xato, setXato] = useState(null); // xato (boshda yo'q)
Boshlang'ich qiymatlarga e'tibor bering: data β null (hali ma'lumot yo'q), yuklanmoqda β true (chunki ilova ochilishi bilan yuklash boshlanadi), xato β null (hali xato yo'q).
useEffect bilan yuklash β to'liq namuna¶
So'rovni qachon yuborish kerak? Komponent ekranda paydo bo'lishi bilan. Buning uchun 11-bobda o'rgangan useEffectdan foydalanamiz: bo'sh bog'liqliklar massivi [] bilan u faqat bir marta, komponent birinchi chizilganda ishlaydi.
Eslatma. 11-bobni eslang:
useEffect(() => { ... }, [])β komponent ekranga chiqqanda bir marta bajariladigan kod. Tarmoq so'rovi uchun aynan shu kerak. Batafsil esa 11 β useEffect bobiga qarang.
Mana to'liq, ishlaydigan namuna. Bunda try/catch/finally bloki uch holatni mukammal boshqaradi:
// app/postlar.tsx
import { useState, useEffect } from 'react';
import { View, Text, FlatList, ActivityIndicator, StyleSheet } from 'react-native';
// Post ma'lumotining tipini aniqlaymiz (TypeScript)
type Post = { id: number; title: string; body: string };
export default function Postlar() {
const [data, setData] = useState<Post[] | null>(null);
const [yuklanmoqda, setYuklanmoqda] = useState(true);
const [xato, setXato] = useState<string | null>(null);
useEffect(() => {
async function yukla() {
try {
setYuklanmoqda(true); // yuklashni boshladik
setXato(null); // oldingi xatoni tozalaymiz
const javob = await fetch('https://jsonplaceholder.typicode.com/posts');
if (!javob.ok) {
// server xato status qaytarsa (masalan 404, 500)
throw new Error(`Server xatosi: ${javob.status}`);
}
const natija: Post[] = await javob.json();
setData(natija); // ma'lumotni saqlaymiz
} catch (e: unknown) {
// tarmoq uzilsa yoki yuqoridagi throw ishlasa shu yerga tushamiz
setXato(e instanceof Error ? e.message : 'Nomalum xato');
} finally {
setYuklanmoqda(false); // har holatda ham yuklash tugadi
}
}
yukla();
}, []); // [] β faqat bir marta, ochilishda
// 1-holat: yuklanmoqda
if (yuklanmoqda) {
return (
<View style={styles.markaz}>
<ActivityIndicator size="large" color="#0ea5e9" />
<Text style={styles.holat}>Yuklanmoqda...</Text>
</View>
);
}
// 2-holat: xato
if (xato) {
return (
<View style={styles.markaz}>
<Text style={styles.xato}>Xato: {xato}</Text>
</View>
);
}
// 3-holat: ma'lumot
return (
<FlatList
data={data}
keyExtractor={(item) => item.id.toString()}
renderItem={({ item }) => (
<View style={styles.karta}>
<Text style={styles.sarlavha}>{item.title}</Text>
<Text style={styles.tana}>{item.body}</Text>
</View>
)}
ListEmptyComponent={<Text style={styles.holat}>Post topilmadi</Text>}
/>
);
}
const styles = StyleSheet.create({
markaz: { flex: 1, alignItems: 'center', justifyContent: 'center', gap: 10 },
holat: { fontSize: 15, color: '#475569' },
xato: { fontSize: 15, color: '#dc2626', textAlign: 'center', paddingHorizontal: 24 },
karta: {
backgroundColor: '#ffffff', padding: 14, marginVertical: 6, marginHorizontal: 12,
borderRadius: 10, borderWidth: 1, borderColor: '#bae6fd',
},
sarlavha: { fontSize: 16, fontWeight: '700', color: '#1e293b' },
tana: { fontSize: 14, color: '#475569', marginTop: 4 },
});
Bu kodni diqqat bilan o'qing β bu butun bobning yuragi. E'tibor bering:
tryichida ma'lumot olamiz. Agar hammasi joyida bo'lsa βsetData.catchxatoni ushlaydi vasetXatoqiladi. Internet yo'qligi ham, server xatosi ham shu yerga keladi.finallyhar doim (ham muvaffaqiyat, ham xatoda) ishlaydi β shuning uchunsetYuklanmoqda(false)ni shu yerga qo'yamiz. Bu spinnerning "abadiy" aylanib qolishining oldini oladi.- UI'da uchta
returnbor: avvalyuklanmoqda, keyinxato, oxirida ma'lumot. Tartib muhim.
Ehtiyot bo'ling.
fetchfaqat tarmoq uzilganda xato (reject) qaytaradi. Server 404 yoki 500 kabi xato status qaytarsa,fetchbuni xato deb hisoblamaydi! Shuning uchun bizif (!javob.ok)bilan o'zimiz tekshirib,throwqilamiz.javob.okβ status 200β299 oralig'ida bo'lsatrue. Bu juda keng uchraydigan tuzoq.Maslahat. Matn har doim
<Text>ichida bo'lishi kerak β bu RN qoidasi.<ActivityIndicator>β bu RN'ning o'rnatilgan aylanuvchi spinneri;size="large"vacolorbilan moslashtiriladi.
Ma'lumot yuborish: POST, PUT, DELETE¶
Hozirgacha biz faqat ma'lumot oldik (GET). Endi ma'lumot yuborishni ham o'rganamiz. Buning uchun fetchga ikkinchi argument β sozlamalar obyekti beramiz.
Bu to'rt metodni birgalikda CRUD deb atashadi: Create (yaratish), Read (o'qish), Update (yangilash), Delete (o'chirish). Ko'pchilik ilovalar shu to'rt amaldan iborat.
POST β yangi ma'lumot qo'shish¶
Yangi post yaratish uchun POST metodi va yuboriladigan ma'lumot (body) kerak:
async function postQoshish(sarlavha: string, tana: string) {
const javob = await fetch('https://jsonplaceholder.typicode.com/posts', {
method: 'POST', // metod β POST
headers: { 'Content-Type': 'application/json' }, // "men JSON yuboryapman"
body: JSON.stringify({ title: sarlavha, body: tana, userId: 1 }), // ma'lumot
});
if (!javob.ok) {
throw new Error(`Qo'shishda xato: ${javob.status}`);
}
const yangiPost = await javob.json();
return yangiPost; // server qaytargan yangi post (id bilan)
}
Bu yerda uchta yangi narsa bor:
method: 'POST'β qanday amal qilishni serverga bildiramiz.headersβ qo'shimcha ma'lumot.'Content-Type': 'application/json'serverga "men JSON formatida ma'lumot yuboryapman" deydi.bodyβ yuboriladigan ma'lumot. U matn bo'lishi shart, shuning uchun obyektniJSON.stringify(...)bilan matnga aylantiramiz.
Hayotiy o'xshatish. GET β bu kutubxonadan kitob olish (faqat o'qiysiz). POST β bu kutubxonaga yangi kitob topshirish (siz biror narsa berasiz). PUT β eski kitobni yangi nashr bilan almashtirish. DELETE β kitobni javondan olib tashlash.
PUT β mavjud ma'lumotni yangilash¶
Mavjud postni o'zgartirish uchun URL'da uning idsini ko'rsatamiz va PUT ishlatamiz:
async function postYangilash(id: number, yangiSarlavha: string) {
await fetch(`https://jsonplaceholder.typicode.com/posts/${id}`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ title: yangiSarlavha }),
});
}
DELETE β o'chirish¶
O'chirish eng sodda β body kerak emas, faqat metod va id:
async function postOchirish(id: number) {
await fetch(`https://jsonplaceholder.typicode.com/posts/${id}`, {
method: 'DELETE',
});
}
JSONPlaceholder haqida
JSONPlaceholder β test API. POST/PUT/DELETE so'rovlari "ishladi" deb javob qaytaradi, lekin haqiqatda hech narsani saqlamaydi (keyingi GET'da yangi postingizni ko'rmaysiz). Bu mashq uchun normal β siz so'rov yuborishni o'rganasiz. Haqiqiy serverda esa o'zgarishlar saqlanadi.
So'rov parametrlari va sarlavhalar¶
Ko'pincha serverga "qaysi" ma'lumotni xohlayotganingizni aytishingiz kerak: faqat 10 ta post, faqat 1-foydalanuvchi postlari, "telefon" so'zi bo'yicha qidiruv va hokazo. Buni so'rov parametrlari (query parameters) orqali aytasiz β ular URL oxiriga ? belgisidan keyin qo'shiladi:
https://jsonplaceholder.typicode.com/posts?userId=1&_limit=5
βββββββββββ¬ββββββββββ
so'rov parametrlari
Bu yerda userId=1 β faqat 1-foydalanuvchi postlari, _limit=5 β faqat 5 ta. Parametrlar bir-biridan & bilan ajraladi.
Hayotiy o'xshatish. So'rov parametrlari β bu kafedagi buyurtmangizga qo'shimcha izoh berishga o'xshaydi: "kofe β shakarsiz, sutli". Asosiy buyurtma bir xil (kofe), lekin parametrlar uni aniqlashtiradi.
URL'ni qo'lda yopishtirish o'rniga, URL obyektidan foydalanish toza va xavfsiz:
async function postlarniOl(foydalanuvchiId: number) {
const url = new URL('https://jsonplaceholder.typicode.com/posts');
url.searchParams.set('userId', String(foydalanuvchiId)); // ?userId=...
url.searchParams.set('_limit', '5'); // &_limit=5
const javob = await fetch(url); // URL obyektini to'g'ridan-to'g'ri beramiz
return await javob.json();
}
Bunda maxsus belgilar (bo'shliq, o'zbekcha harflar) avtomatik to'g'ri kodlanadi β qo'lda yopishtirilganda esa xato chiqishi mumkin.
Sarlavhalar (headers) esa so'rov haqida qo'shimcha ma'lumot beradi. Eng keng tarqalganlari:
'Content-Type': 'application/json'β "men JSON yuboryapman" (POST/PUT'da kerak).'Authorization': 'Bearer <token>'β "men kimligimni token bilan tasdiqlayman" (himoyalangan API'larda).'Accept': 'application/json'β "menga JSON qaytaring".
const javob = await fetch('https://api.example.com/profil', {
headers: {
'Authorization': `Bearer ${token}`, // token bilan kirish
'Accept': 'application/json',
},
});
Eslatma. Token va himoyalangan so'rovlar haqida 25 β Autentifikatsiya bobida batafsil gaplashamiz. Hozircha shuni biling: ko'p API'lar har so'rovda kim ekanligingizni
Authorizationsarlavhasi orqali so'raydi.
axios β mashhur muqobil¶
fetch yetarli, lekin ko'plab loyihalarda axios nomli kutubxona ishlatiladi. U fetchga qaraganda biroz qulayroq. O'rnatish:
Bir xil GET so'rovini axios bilan solishtiring:
import axios from 'axios';
// GET β javob to'g'ridan-to'g'ri .data ichida
const javob = await axios.get('https://jsonplaceholder.typicode.com/posts');
const postlar = javob.data; // .json() chaqirish SHART EMAS!
// POST β ikkinchi argument to'g'ridan-to'g'ri ma'lumot
await axios.post('https://jsonplaceholder.typicode.com/posts', {
title: 'Yangi post',
body: 'Matn',
userId: 1,
});
fetch va axios farqlari:
| Xususiyat | fetch (o'rnatilgan) |
axios (kutubxona) |
|---|---|---|
| O'rnatish | Kerak emas | npm install axios |
| JSON aylantirish | Qo'lda: await javob.json() |
Avtomatik: javob.data |
| Xato statuslar (404/500) | O'zingiz javob.ok tekshirasiz |
Avtomatik catchga tushadi |
body |
JSON.stringify(...) qilasiz |
Obyektni to'g'ridan-to'g'ri berasiz |
| Interceptor (oraliq qayta ishlash) | Yo'q | Bor (qulay) |
axiosning eng kuchli tomoni β interceptor, ya'ni har bir so'rovga avtomatik biror narsa qo'shish imkoni. Masalan, har so'rovga autentifikatsiya tokenini qo'shish:
import axios from 'axios';
// Markaziy sozlama β barcha so'rovlar shu manzildan boshlanadi
const api = axios.create({ baseURL: 'https://jsonplaceholder.typicode.com' });
// Interceptor: har bir so'rovga token qo'shamiz
api.interceptors.request.use((config) => {
const token = 'foydalanuvchi-tokeni'; // odatda saqlangan joydan olinadi
config.headers.Authorization = `Bearer ${token}`;
return config;
});
// Endi har bir api.get/post avtomatik tokenni o'z ichiga oladi
const javob = await api.get('/posts');
Maslahat. Boshlovchi sifatida
fetchdan boshlang β u hech narsa o'rnatmasdan ishlaydi va asoslarni o'rgatadi. Loyihangiz kattalashganda, ko'p so'rov bo'lsa yoki tokenlar bilan ishlasangiz β axiosga o'tish qulay. Token va autentifikatsiya haqida 25 β Autentifikatsiya bobida gaplashamiz.
Xatolarni chiroyli ishlash¶
Yomon internet β hayotning bir qismi. Yaxshi ilova xatoga "qulamaydi", balki foydalanuvchiga tushunarli xabar beradi. Uch xil xatoni ajratish foydali:
- Tarmoq xatosi β internet yo'q, server javob bermadi.
fetchto'g'ridan-to'g'ricatchga tashlaydi. - HTTP status xatosi β server javob berdi, lekin xato bilan (404 β topilmadi, 500 β server xatosi, 401 β ruxsat yo'q). Buni
javob.okyokijavob.statusbilan tekshiramiz. - Timeout β server juda sekin javob beryapti. Buni
AbortControllerbilan to'xtatamiz (quyida).
Foydalanuvchiga texnik xatoni emas, tushunarli xabar ko'rsating:
catch (e: unknown) {
let xabar = 'Nimadir xato ketdi. Qaytadan urinib ko\'ring.';
if (e instanceof TypeError) {
// ko'pincha internet yo'qligi shu xatoni beradi
xabar = 'Internet aloqasi yo\'q. Ulanishni tekshiring.';
} else if (e instanceof Error) {
xabar = e.message; // bizning throw qilgan xabarimiz
}
setXato(xabar);
}
Ehtiyot bo'ling. Foydalanuvchiga
TypeError: Network request failedkabi texnik xatolarni ko'rsatmang β ular tushunarsiz va qo'rqitadi. Har doim oddiy tildagi xabar bering: "Internet yo'q", "Server javob bermadi", "Qayta urinib ko'ring". Xato yonida "Qayta urinish" tugmasini qo'ying β bu eng yaxshi UX amaliyotlaridan biri.
useFetch β qayta ishlatiladigan custom hook¶
Har bir ekranga useState (Γ3) + useEffect + try/catch/finally yozish charchatadi va takrorlanadi. 13-bobda o'rgangan custom hook g'oyasi aynan shu uchun: takrorlanuvchi mantiqni bitta funksiyaga yig'amiz.
Eslatma. Custom hook β bu
usebilan boshlanadigan, ichida boshqa hooklar ishlatadigan funksiya. U bir necha komponent o'rtasida mantiqni ulashish imkonini beradi. Batafsil: 13 β Custom hooklar va tuzilish.
Mana to'liq, qayta ishlatiladigan useFetch hooki. U URL'ni qabul qiladi va { data, yuklanmoqda, xato, qaytaYukla } qaytaradi:
// hooks/useFetch.ts
import { useState, useEffect, useCallback } from 'react';
type FetchHolati<T> = {
data: T | null;
yuklanmoqda: boolean;
xato: string | null;
qaytaYukla: () => void;
};
export function useFetch<T>(url: string): FetchHolati<T> {
const [data, setData] = useState<T | null>(null);
const [yuklanmoqda, setYuklanmoqda] = useState(true);
const [xato, setXato] = useState<string | null>(null);
const [sanagich, setSanagich] = useState(0); // qayta yuklash uchun
// qaytaYukla β sanagichni oshirib, useEffect'ni qaytadan ishga tushiramiz
const qaytaYukla = useCallback(() => setSanagich((s) => s + 1), []);
useEffect(() => {
const controller = new AbortController(); // so'rovni bekor qilish uchun
async function yukla() {
try {
setYuklanmoqda(true);
setXato(null);
const javob = await fetch(url, { signal: controller.signal });
if (!javob.ok) {
throw new Error(`HTTP xatosi: ${javob.status}`);
}
const natija: T = await javob.json();
setData(natija);
} catch (e: unknown) {
// bekor qilingan so'rov β bu xato emas, jim qolamiz
if (e instanceof Error && e.name === 'AbortError') return;
setXato(e instanceof Error ? e.message : 'Nomalum xato');
} finally {
setYuklanmoqda(false);
}
}
yukla();
return () => controller.abort(); // tozalash: komponent yo'qolsa bekor qil
}, [url, sanagich]); // url o'zgarsa yoki qaytaYukla bosilsa β qayta yukla
return { data, yuklanmoqda, xato, qaytaYukla };
}
Bu hook <T> (generik tip) bilan ishlaydi, ya'ni har qanday ma'lumot turi uchun mos. Endi istalgan ekranda bir qator bilan ishlatasiz:
// app/postlar.tsx
import { useFetch } from '../hooks/useFetch';
type Post = { id: number; title: string };
export default function Postlar() {
const { data, yuklanmoqda, xato, qaytaYukla } = useFetch<Post[]>(
'https://jsonplaceholder.typicode.com/posts'
);
// ...endi data/yuklanmoqda/xato'ni UI'da ishlatamiz (uch holat)
}
Mana custom hookning kuchi: barcha murakkab mantiq yashiringan, har ekranda atigi bitta qator. Bu DRY (Don't Repeat Yourself β "takrorlama") tamoyili.
AbortController β so'rovni bekor qilish (tozalash)¶
Tasavvur qiling: foydalanuvchi profil ekranini ochdi (so'rov boshlandi), lekin javob kelishidan oldin orqaga qaytdi. Komponent ekrandan yo'qoldi, lekin so'rov hali "havoda". Javob kelganda setData qilishga urinadi β bu komponent yo'q bo'lib ketgan! Bu xotira oqishi (memory leak) va ogohlantirishlarga olib keladi.
Hayotiy o'xshatish. Bu xuddi taksi chaqirib, keyin o'zingiz boshqa yo'l bilan ketib qolganingizdek. Taksi kelganda siz yo'qsiz. To'g'risi β ketishdan oldin buyurtmani bekor qilish.
AbortControlleraynan shu β "endi javob kerak emas" deb so'rovni bekor qiladi.
Buning yechimi β AbortController va useEffectning tozalash funksiyasi (11-bobni eslang):
useEffect(() => {
const controller = new AbortController();
async function yukla() {
try {
const javob = await fetch(url, { signal: controller.signal });
const data = await javob.json();
setData(data);
} catch (e: unknown) {
if (e instanceof Error && e.name === 'AbortError') return; // bekor qilindi
// boshqa xatolar...
}
}
yukla();
// tozalash: komponent yo'qolsa yoki url o'zgarsa β so'rovni bekor qil
return () => controller.abort();
}, [url]);
Yuqoridagi useFetch hookida bu allaqachon bor β shuning uchun u "to'g'ri" hook hisoblanadi. Tozalash (cleanup) haqida batafsil: 11 β useEffect va obunalarni boshqarish haqida 12 β Hooklar chuqurroq.
Ma'lumotni yangilash: pull-to-refresh¶
Mobil ilovalarda eng tabiiy "yangilash" usuli β ro'yxatni pastga tortish (pull-to-refresh). 8-bobda FlatListni o'rgangan edik; uning refreshControl xususiyati shu uchun:
import { FlatList, RefreshControl, View, Text, StyleSheet } from 'react-native';
import { useFetch } from '../hooks/useFetch';
type Post = { id: number; title: string };
export default function Postlar() {
const { data, yuklanmoqda, xato, qaytaYukla } = useFetch<Post[]>(
'https://jsonplaceholder.typicode.com/posts'
);
return (
<FlatList
data={data}
keyExtractor={(item) => item.id.toString()}
renderItem={({ item }) => (
<View style={styles.karta}>
<Text style={styles.sarlavha}>{item.title}</Text>
</View>
)}
// pastga tortilganda qaytaYukla ishga tushadi
refreshControl={
<RefreshControl refreshing={yuklanmoqda} onRefresh={qaytaYukla} />
}
/>
);
}
const styles = StyleSheet.create({
karta: { backgroundColor: '#fff', padding: 14, margin: 8, borderRadius: 10 },
sarlavha: { fontSize: 16, color: '#1e293b' },
});
RefreshControl β bu RN komponenti. refreshing (yuklanyaptimi?) va onRefresh (tortilganda nima qilish) ikki xususiyatini oladi. Foydalanuvchi ro'yxatni pastga tortsa β qaytaYukla ishlaydi, hookimiz so'rovni yangilaydi.
Keshlash va TanStack Query
Ilovangiz o'sgan sayin "keshlash" (cache β bir marta yuklangan ma'lumotni saqlab, qayta-qayta yuklamaslik) muhim bo'ladi. Buni qo'lda yozish murakkab. TanStack Query (@tanstack/react-query) nomli kutubxona buni avtomatik qiladi: keshlash, qayta yuklash, fon yangilash, xatoda qayta urinish β barchasi tayyor. Ko'p ma'lumot bilan ishlaydigan jiddiy ilovalar uchun uni o'rganishni tavsiya qilamiz. Hozircha useFetch asoslarni mukammal beradi.
To'liq misol: postlar ro'yxati ilovasi¶
Endi hamma bilimni birlashtiramiz. Quyidagi ekran real API'dan postlarni yuklaydi, uch holatni to'liq boshqaradi, pull-to-refresh va "Qayta urinish" tugmasini o'z ichiga oladi. Bu kod jonli loyihada tsc bilan sinab ko'rilgan β ishonch bilan ishlating:
// app/postlar.tsx
import { useState, useEffect, useCallback } from 'react';
import {
View, Text, FlatList, ActivityIndicator, Pressable, RefreshControl, StyleSheet,
} from 'react-native';
type Post = { id: number; title: string; body: string };
export default function Postlar() {
const [data, setData] = useState<Post[] | null>(null);
const [yuklanmoqda, setYuklanmoqda] = useState(true);
const [xato, setXato] = useState<string | null>(null);
// useCallback β funksiya har renderda qayta yaratilmasligi uchun
const yukla = useCallback(async () => {
try {
setYuklanmoqda(true);
setXato(null);
const javob = await fetch('https://jsonplaceholder.typicode.com/posts');
if (!javob.ok) {
throw new Error(`Server xatosi: ${javob.status}`);
}
const natija: Post[] = await javob.json();
setData(natija);
} catch (e: unknown) {
setXato(e instanceof Error ? e.message : 'Nimadir xato ketdi');
} finally {
setYuklanmoqda(false);
}
}, []);
useEffect(() => {
yukla();
}, [yukla]);
// 1-holat: birinchi yuklash (hali ma'lumot yo'q)
if (yuklanmoqda && !data) {
return (
<View style={styles.markaz}>
<ActivityIndicator size="large" color="#0ea5e9" />
<Text style={styles.holat}>Postlar yuklanmoqda...</Text>
</View>
);
}
// 2-holat: xato (va ma'lumot ham yo'q)
if (xato && !data) {
return (
<View style={styles.markaz}>
<Text style={styles.xato}>{xato}</Text>
<Pressable style={styles.tugma} onPress={yukla}>
<Text style={styles.tugmaMatn}>Qayta urinish</Text>
</Pressable>
</View>
);
}
// 3-holat: ma'lumot ro'yxati
return (
<FlatList
data={data}
keyExtractor={(item) => item.id.toString()}
contentContainerStyle={styles.royxat}
renderItem={({ item }) => (
<View style={styles.karta}>
<Text style={styles.sarlavha} numberOfLines={1}>{item.title}</Text>
<Text style={styles.tana} numberOfLines={2}>{item.body}</Text>
</View>
)}
ListEmptyComponent={<Text style={styles.holat}>Hech qanday post yo'q</Text>}
refreshControl={
<RefreshControl refreshing={yuklanmoqda} onRefresh={yukla} />
}
/>
);
}
const styles = StyleSheet.create({
markaz: { flex: 1, alignItems: 'center', justifyContent: 'center', gap: 12, padding: 24 },
holat: { fontSize: 15, color: '#475569' },
xato: { fontSize: 15, color: '#dc2626', textAlign: 'center' },
royxat: { padding: 12, gap: 10 },
karta: {
backgroundColor: '#ffffff', padding: 16, borderRadius: 12,
borderWidth: 1, borderColor: '#bae6fd',
},
sarlavha: { fontSize: 16, fontWeight: '700', color: '#1e293b' },
tana: { fontSize: 14, color: '#475569', marginTop: 6 },
tugma: {
backgroundColor: '#4f46e5', paddingVertical: 12, paddingHorizontal: 28,
borderRadius: 10,
},
tugmaMatn: { color: '#fff', fontWeight: '600', fontSize: 15 },
});
E'tibor bering, bu to'liq misolda biz holatlarni biroz nozikroq tekshiramiz:
yuklanmoqda && !dataβ bu birinchi yuklash (hali hech narsa yo'q). To'liq ekran spinner.xato && !dataβ xato bo'ldi va ko'rsatadigan ma'lumot ham yo'q. To'liq ekran xato + tugma.- Aks holda β ma'lumotni ko'rsatamiz.
refreshing={yuklanmoqda}esa pull-to-refresh spinnerini boshqaradi (ma'lumot allaqachon ekranda turganda).
Maslahat.
numberOfLinesxususiyati matnni ko'rsatilgan qatordan oshmasligini ta'minlaydi (uzun matn...bilan kesiladi). Uzun sarlavhalar va matnlarda kartani toza saqlash uchun foydali.
Xulosa¶
- API β ikki dastur o'rtasidagi muloqot qoidalari; REST API har ma'lumotga URL + HTTP metod orqali murojaat qiladi va ko'pincha JSON qaytaradi.
fetchβ RN'ga o'rnatilgan tarmoq vositasi. Ikki qadam:const javob = await fetch(url)vaconst data = await javob.json().async/awaitishlating.- Uch holat (loading / error / data) β har bir so'rovning asosi. Uchta
useStatebilan boshqaring va har birini UI'da ko'rsating. Faqat "data"ni ko'rsatish β eng keng tarqalgan boshlovchi xatosi. useEffect(() => { yukla(); }, [])β komponent ochilganda bir marta yuklash.try/catch/finallyuch holatni mukammal boshqaradi;finallydasetYuklanmoqda(false).fetch404/500'ni xato deb hisoblamaydi βif (!javob.ok)bilan o'zingiz tekshiring vathrowqiling.- POST/PUT/DELETE β
fetch(url, { method, headers, body: JSON.stringify(...) })bilan ma'lumot yuborasiz. Bu CRUD amallari. axiosβ qulay muqobil: avtomatik JSON (javob.data), xato statuslar avtomatikcatchga tushadi, interceptor bilan tokenlar qo'shiladi.useFetchcustom hook takror kodni yo'qotadi;AbortControllerkomponent yo'qolganda so'rovni bekor qiladi;RefreshControlpull-to-refresh beradi.
Amaliy mashqlar¶
-
Foydalanuvchilar ro'yxati (uch holat).
https://jsonplaceholder.typicode.com/usersmanzilidan foydalanuvchilarni yuklang.ActivityIndicator(yuklanmoqda), xato matni (xato) vaFlatList(ma'lumot) β uch holatni to'liq ko'rsating. Har foydalanuvchi uchun ism va email'ni karta ichida chiqaring. -
javob.oktuzog'i. Bilatdan noto'g'ri URL bering (masalan.../postlarrr).if (!javob.ok)tekshiruvisiz nima bo'lishini kuzating, keyin tekshiruvni qo'shing va farqni ko'ring. Foydalanuvchiga tushunarli xato xabarini yozing. -
Yangi post qo'shish (POST).
TextInputva tugma bilan kichik forma yarating. Tugma bosilgandaPOSTso'rovi yuboring (sarlavha + matn). "Yuborilmoqda..." holatini ko'rsating va server qaytarganidni ekranda chiqaring. Tugmani yuborish vaqtidadisabledqiling. -
useFetchhookini ajrating. YuqoridagiuseFetchhookini alohidahooks/useFetch.tsfayliga ko'chiring va kamida ikki xil ekranda (postlar va foydalanuvchilar) ishlating. Generik<T>to'g'ri ishlashiga ishonch hosil qiling. -
Pull-to-refresh + qayta urinish. Postlar ro'yxatiga
RefreshControlqo'shing. Xato holatida "Qayta urinish" tugmasini chiqaring. Qiyinroq: o'chirilgan internetda nima bo'lishini sinab ko'ring (Wi-Fi'ni o'chiring) va xato xabaringiz tushunarli ekanligiga ishonch hosil qiling.
β¬ οΈ Oldingi: 16 β Dinamik marshrut va parametrlar Β· π Kitob boshi Β· Keyingi: 18 β Lokal saqlash β‘οΈ