Fetch va Axios — React da HTTP so'rovlar

~20 daq · React · Ma'lumot olish

Muammodan boshlaylik

React komponentlari o'z ichidagi ma'lumotlar bilan ishlaydi — useState, props. Lekin haqiqiy ilovalar serverdan ma'lumot oladi: foydalanuvchilar ro'yxati, mahsulotlar, buyurtmalar.

Server bilan qanday gaplashiladi? HTTP so'rovlar orqali. React ning o'zida bu uchun maxsus vosita yo'q. Brauzer o'rnatilgan fetch API si bor — yoki axios kutubxonasini o'rnatish mumkin.

Bu darsda ikkalasini ham ko'ramiz: qanday ishlaydi, farqlari nima, qachon qaysi birini tanlash kerak.


fetch — brauzer o'rnatilgan API

fetch — zamonaviy brauzerlarga o'rnatilgan funksiya. Hech narsa o'rnatmasdan ishlatiladi. Promise qaytaradi.

fetch('https://jsonplaceholder.typicode.com/posts/1')
  .then((javob) => javob.json())
  .then((malumot) => console.log(malumot));

Nima uchun ikki marta .then()? Birinchisi — HTTP javobini oladi (sarlavhalar, status). Ikkinchisi — javob tanasini (body) JSON ga o'giradi. Bu asinxron jarayon — shuning uchun alohida .then().


React da fetch — useEffect bilan

Komponent yuklanganida server dan ma'lumot olish:

import { useState, useEffect } from 'react';

function Foydalanuvchi() {
  const [malumot, setMalumot] = useState(null);

  useEffect(() => {
    fetch('https://jsonplaceholder.typicode.com/users/1')
      .then((javob) => javob.json())
      .then((data) => setMalumot(data));
  }, []); // ← bo'sh array — faqat bir marta

  if (!malumot) return <p>Yuklanmoqda...</p>;

  return <h1>{malumot.name}</h1>;
}

Bu ishlaydi — lekin xato holati ko'rib chiqilmagan. Haqiqiy ilovada xatolarni ham boshqarish kerak.


fetch — xato boshqarish

fetch ning o'ziga xos muammosi bor: u faqat tarmoq xatosida Promise ni rad etadi. Server 404, 500 qaytarsa — fetch buni xato deb hisoblamaydi, ok: false deb javob beradi.

useEffect(() => {
  fetch('https://jsonplaceholder.typicode.com/users/1')
    .then((javob) => {
      if (!javob.ok) {
        throw new Error(`Server xatosi: ${javob.status}`);
      }
      return javob.json();
    })
    .then((data) => setMalumot(data))
    .catch((err) => setXato(err.message));
}, []);

javob.ok — status 200-299 orasida bo'lsa true. javob.status — aniq status kodi (404, 500 va h.k.).


async/await bilan yozish

.then() zanjirlari o'rniga async/await — o'qish osonroq:

import { useState, useEffect } from 'react';

function Foydalanuvchilar() {
  const [royxat, setRoyxat] = useState([]);
  const [yuklanmoqda, setYuklanmoqda] = useState(true);
  const [xato, setXato] = useState('');

  useEffect(() => {
    async function malumotOl() {
      try {
        const javob = await fetch('https://jsonplaceholder.typicode.com/users');

        if (!javob.ok) {
          throw new Error(`Xato: ${javob.status}`);
        }

        const data = await javob.json();
        setRoyxat(data);
      } catch (err) {
        setXato(err.message);
      } finally {
        setYuklanmoqda(false); // ← muvaffaqiyatli bo'lsa ham, xato bo'lsa ham
      }
    }

    malumotOl();
  }, []);

  if (yuklanmoqda) return <p>Yuklanmoqda...</p>;
  if (xato) return <p style={{ color: 'red' }}>Xato: {xato}</p>;

  return (
    <ul>
      {royxat.map((f) => (
        <li key={f.id}>{f.name}</li>
      ))}
    </ul>
  );
}

useEffect ichida async function e'lon qilinadi, keyin chaqiriladi. Nima uchun to'g'ridan-to'g'ri async () => {} emas? Chunki useEffect callback async bo'lsa Promise qaytaradi — React bu Promise bilan nima qilishni bilmaydi va cleanup funksiyasini kutadi.


Axios nima?

Axios — HTTP so'rovlar uchun mashhur kutubxona. fetch ga qaraganda bir nechta qulay farqi bor.

O'rnatish:

npm install axios

Asosiy ishlatilish:

import axios from 'axios';

const javob = await axios.get('https://jsonplaceholder.typicode.com/users');
console.log(javob.data); // ← to'g'ridan-to'g'ri ma'lumot

fetch da ikki qadam — response.json() — kerak bo'lsa, Axios da ma'lumot response.data da tayyor turibdi.


fetch vs Axios — farqlar

1. JSON avtomatik parse qilish:

// fetch — ikki qadam
const javob = await fetch(url);
const data = await javob.json(); // ← qo'shimcha qadam

// Axios — bir qadam
const javob = await axios.get(url);
const data = javob.data; // ← tayyor

2. Xato boshqarish:

// fetch — 404/500 ni xato deb hisoblamaydi
const javob = await fetch(url);
if (!javob.ok) throw new Error('Xato'); // ← qo'lda tekshirish

// Axios — 4xx/5xx da avtomatik xato chiqaradi
try {
  await axios.get(url);
} catch (err) {
  console.log(err.response.status); // 404, 500 va h.k.
}

3. So'rov bekor qilish:

// fetch — AbortController (50-darsda batafsil)
const controller = new AbortController();
fetch(url, { signal: controller.signal });
controller.abort();

// Axios — CancelToken yoki AbortController
const controller = new AbortController();
axios.get(url, { signal: controller.signal });
controller.abort();

4. Interceptor — so'rov/javobni ushlab olish:

// Axios da qulay interceptor API bor (85-darsda batafsil)
axios.interceptors.request.use((config) => {
  config.headers.Authorization = `Bearer ${token}`;
  return config;
});

fetch da interceptor yo'q — har so'rovga qo'lda header qo'shiladi.

5. Taraqqiyot (progress) kuzatish:

// Axios — fayl yuklashda progress
axios.post(url, fayl, {
  onUploadProgress: (e) => {
    const foiz = Math.round((e.loaded / e.total) * 100);
    setProgress(foiz);
  },
});
// fetch da bu mumkin emas (ReadableStream bilan murakkab yechim bor)

Axios — amaliy misol

import { useState, useEffect } from 'react';
import axios from 'axios';

function Mahsulotlar() {
  const [mahsulotlar, setMahsulotlar] = useState([]);
  const [yuklanmoqda, setYuklanmoqda] = useState(true);
  const [xato, setXato] = useState('');

  useEffect(() => {
    async function malumotOl() {
      try {
        const javob = await axios.get('/api/mahsulotlar');
        setMahsulotlar(javob.data);
      } catch (err) {
        if (err.response) {
          // Server javob berdi, lekin 4xx/5xx
          setXato(`Server xatosi: ${err.response.status}`);
        } else if (err.request) {
          // So'rov yuborildi, lekin javob kelmadi
          setXato('Server bilan aloqa yo\'q');
        } else {
          // Boshqa xato
          setXato(err.message);
        }
      } finally {
        setYuklanmoqda(false);
      }
    }

    malumotOl();
  }, []);

  if (yuklanmoqda) return <p>Yuklanmoqda...</p>;
  if (xato) return <p style={{ color: 'red' }}>{xato}</p>;

  return (
    <ul>
      {mahsulotlar.map((m) => (
        <li key={m.id}>{m.nomi} — {m.narxi} so'm</li>
      ))}
    </ul>
  );
}

Axios instance — asosiy sozlamalar

Har so'rovda bir xil baseURL va headers yozmaslik uchun Axios instance yaratiladi:

// src/api/axios.js
import axios from 'axios';

const api = axios.create({
  baseURL: 'https://api.misol.uz',   // ← asosiy URL
  timeout: 10000,                     // ← 10 soniya kutish
  headers: {
    'Content-Type': 'application/json',
  },
});

export default api;
// Komponentda — to'liq URL emas, faqat yo'l
import api from '../api/axios';

const javob = await api.get('/mahsulotlar');       // GET /mahsulotlar
const javob = await api.post('/buyurtma', data);   // POST /buyurtma
const javob = await api.put('/mahsulot/42', data); // PUT /mahsulot/42
const javob = await api.delete('/mahsulot/42');    // DELETE /mahsulot/42

POST so'rov — ma'lumot yuborish

import { useState } from 'react';
import api from '../api/axios';

function MahsulotQoshish() {
  const [nomi, setNomi] = useState('');
  const [narxi, setNarxi] = useState('');
  const [yuklanmoqda, setYuklanmoqda] = useState(false);

  async function yuborish(e) {
    e.preventDefault();
    setYuklanmoqda(true);

    try {
      const javob = await api.post('/mahsulotlar', {
        nomi,
        narxi: Number(narxi),
      });
      console.log('Qo\'shildi:', javob.data);
      setNomi('');
      setNarxi('');
    } catch (err) {
      console.error('Xato:', err.message);
    } finally {
      setYuklanmoqda(false);
    }
  }

  return (
    <form onSubmit={yuborish}>
      <input
        value={nomi}
        onChange={(e) => setNomi(e.target.value)}
        placeholder="Mahsulot nomi"
      />
      <input
        value={narxi}
        onChange={(e) => setNarxi(e.target.value)}
        placeholder="Narxi"
        type="number"
      />
      <button type="submit" disabled={yuklanmoqda}>
        {yuklanmoqda ? 'Saqlanmoqda...' : 'Saqlash'}
      </button>
    </form>
  );
}

Tez-tez uchraydigan xatolar

1. fetch da javob.ok ni tekshirmaslik

// ❌ Xato — 404 da ham ma'lumot set qilinadi (undefined)
useEffect(() => {
  fetch('/api/foydalanuvchi/999')
    .then((j) => j.json())
    .then((d) => setMalumot(d));
    // Server "Not Found" xabarini qaytardi — bu ham JSON
    // malumot = { message: "Not found" } — xato sifatida ko'rsatilmaydi
}, []);

// ✅ To'g'ri — ok tekshiriladi
useEffect(() => {
  fetch('/api/foydalanuvchi/999')
    .then((j) => {
      if (!j.ok) throw new Error(`${j.status}`);
      return j.json();
    })
    .then((d) => setMalumot(d))
    .catch((err) => setXato(err.message));
}, []);

Sababi: fetch faqat tarmoq uzilganda xato chiqaradi. Server 404 yoki 500 qaytarsa — bu fetch uchun muvaffaqiyatli javob. response.ok ni tekshirishni unutsangiz, xato holatlari ko'rinmaydi.


2. useEffect ichida to'g'ridan-to'g'ri async

// ❌ Xato — useEffect async bo'lmasligi kerak
useEffect(async () => {
  const data = await fetch(url).then((j) => j.json());
  setMalumot(data);
}, []);
// React konsolda ogohlantirish chiqaradi

// ✅ To'g'ri — ichida async funksiya e'lon qilib chaqirish
useEffect(() => {
  async function olish() {
    const data = await fetch(url).then((j) => j.json());
    setMalumot(data);
  }
  olish();
}, []);

Sababi: useEffect callback yoki undefined, yoki cleanup funksiyasi qaytarishi kerak. async funksiya Promise qaytaradi — React uni cleanup funksiyasi deb bilmaydi va ogohlantirish chiqaradi.


3. Komponent unmount bo'lgandan keyin state set qilish

// ❌ Muammo — komponent yo'qolsa ham set qilishga uriniladi
useEffect(() => {
  fetch(url)
    .then((j) => j.json())
    .then((d) => setMalumot(d)); // ← komponent yo'q bo'lsa xato
}, []);

// ✅ To'g'ri — AbortController bilan (50-darsda batafsil)
useEffect(() => {
  const controller = new AbortController();

  fetch(url, { signal: controller.signal })
    .then((j) => j.json())
    .then((d) => setMalumot(d))
    .catch((err) => {
      if (err.name !== 'AbortError') setXato(err.message);
    });

  return () => controller.abort(); // ← cleanup: so'rovni bekor qil
}, []);

Sababi: Foydalanuvchi sahifadan chiqib ketsa, komponent unmount bo'ladi. Lekin so'rov davom etadi va javob kelganda setMalumot chaqiriladi — yo'q komponentga. React konsol da "Can't perform a React state update on an unmounted component" ogohlantirishini beradi. Bu 50-darsda batafsil ko'riladi.


Qachon fetch, qachon Axios?

fetch ishlating:

  • Kichik loyiha, minimal dependency kerak
  • Faqat oddiy GET so'rovlar
  • Bundle hajmini kamaytirish muhim

Axios ishlating:

  • Ko'p so'rovlar, interceptor kerak
  • Token avtomatik qo'shiladigan API
  • Fayl yuklash va progress kuzatish
  • Katta jamoa loyihasi — izchil xato boshqarish muhim

Amalda aksariyat React loyihalarida Axios yoki TanStack Query (51-55 darslar) ishlatiladi — fetch ni qo'lda ishlatish kamroq.


Xulosa

  • fetch — brauzerga o'rnatilgan, o'rnatish shart emas
  • Axios — qulay API, avtomatik JSON, xato boshqarish yaxshiroq
  • fetch da response.ok ni tekshirish shart — aks holda 4xx xato ko'rinmaydi
  • useEffect ichida async function e'lon qilib chaqiriladi
  • Axios instance — baseURL va umumiy sozlamalar bir joyda
  • POST, PUT, DELETE — axios.post(url, data), api.put(url, data), api.delete(url)
  • Komponent unmount bo'lganda so'rovni bekor qilish — AbortController

Keyingi dars: 49-dars: Loading, Error, Success holatlari boshqarish