React: serverdan ma'lumot yuklash

Shu paytgacha ma’lumot kodning o’zida yozilgan edi. Haqiqiy ilovada u serverdan keladi. useEffect darsida yon ta’sirlarni ko’rdik — tarmoq so’rovi ham yon ta’sir. Bu darsda ikkalasini birlashtiramiz.

Uchta holat

Serverdan ma’lumot olish bir zumda bo’lmaydi. Vaqt oralig’ida ekranda nima ko’rsatish kerak? Har so’rov uchta holatdan birida bo’ladi:

Holat Ekranda
Yuklanmoqda Kutish belgisi
Xato Xabar va qayta urinish tugmasi
Tayyor Ma’lumot

Boshlovchilar odatda faqat uchinchisini yozadi. Natijada sekin internetda foydalanuvchi bo’sh ekranga qaraydi va ilova buzilgan deb o’ylaydi.

Shuning uchun uchta holat uchun uchta useState kerak:

const [users, setUsers] = useState([]);
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState(null);

isLoading boshlang’ich qiymati true — komponent paydo bo’lishi bilan so’rov boshlanadi.

Birinchi so’rov

To’liq ishlaydigan misol:

// src/components/UserList.jsx
import { useState, useEffect } from 'react';

function UserList() {
  const [users, setUsers] = useState([]);
  const [isLoading, setIsLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    async function loadUsers() {
      try {
        setIsLoading(true);
        setError(null);

        const response = await fetch("https://jsonplaceholder.typicode.com/users");

        if (!response.ok) {
          throw new Error(`Server javobi: ${response.status}`);
        }

        const data = await response.json();
        setUsers(data);
      } catch (err) {
        setError(err.message);
      } finally {
        setIsLoading(false);
      }
    }

    loadUsers();
  }, []);

  if (isLoading) {
    return <p>Yuklanmoqda...</p>;
  }

  if (error) {
    return <p className="error">Xato: {error}</p>;
  }

  return (
    <ul>
      {users.map((user) => (
        <li key={user.id}>
          {user.name} — {user.email}
        </li>
      ))}
    </ul>
  );
}

export default UserList;

Brauzerda bir lahza “Yuklanmoqda…” ko’rinadi, keyin o’nta foydalanuvchi chiqadi:

Leanne Graham — Sincere@april.biz
Ervin Howell — Shanna@melissa.tv
...

Kodni qismlarga ajratamiz.

async funksiyani effekt ichida e’lon qiling

useEffect ning o’zini async qilib bo’lmaydi:

// ❌ Xato
useEffect(async () => {
  const response = await fetch(url);
}, []);

Sabab: async funksiya har doim Promise qaytaradi, useEffect esa qaytarilgan qiymatni tozalash funksiyasi deb tushunadi. Promise’ni chaqirishga urinib xato beradi.

To’g’ri yo’l — ichida async funksiya e’lon qilib, darrov chaqirish:

// ✅ To'g'ri
useEffect(() => {
  async function loadUsers() {
    // ...
  }

  loadUsers();
}, []);

response.ok ni tekshiring

fetch tarmoq xatosida Promise’ni rad qiladi, lekin server 404 yoki 500 qaytarsa xato deb hisoblamaydi:

// Mavjud bo'lmagan foydalanuvchi
const response = await fetch("https://jsonplaceholder.typicode.com/users/99999");
console.log(response.status);  // 404
console.log(response.ok);      // false

catch bloki bu holatda ishlamaydi. Shuning uchun response.ok ni qo’lda tekshirib, o’zingiz xato chiqarasiz:

if (!response.ok) {
  throw new Error(`Server javobi: ${response.status}`);
}

Bu fetch darsidagi qoidaning o’zi — React uni o’zgartirmaydi.

finally — har holatda bajariladi

finally bloki muvaffaqiyatda ham, xatoda ham ishlaydi:

} finally {
  setIsLoading(false);
}

Uni yozmasangiz, xato yuz berganda isLoading true bo’lib qoladi va ekranda abadiy “Yuklanmoqda…” turadi. Foydalanuvchi xatoni ham ko’rmaydi.

So’rovni bekor qilish

Muammo shunday paydo bo’ladi: foydalanuvchi sahifani ochdi, so’rov ketdi, lekin javob kelguncha u boshqa sahifaga o’tdi. Komponent ekrandan ketgan, javob esa kelaveradi va setUsers chaqiriladi.

Yechim — AbortController:

import { useState, useEffect } from 'react';

function UserList({ pageSize }) {
  const [users, setUsers] = useState([]);
  const [isLoading, setIsLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    const controller = new AbortController();

    async function loadUsers() {
      try {
        setIsLoading(true);
        setError(null);

        const response = await fetch(
          `https://jsonplaceholder.typicode.com/users?_limit=${pageSize}`,
          { signal: controller.signal }
        );

        if (!response.ok) {
          throw new Error(`Server javobi: ${response.status}`);
        }

        const data = await response.json();
        setUsers(data);
      } catch (err) {
        if (err.name === "AbortError") {
          return;
        }
        setError(err.message);
      } finally {
        setIsLoading(false);
      }
    }

    loadUsers();

    return () => {
      controller.abort();
    };
  }, [pageSize]);

  if (isLoading) return <p>Yuklanmoqda...</p>;
  if (error) return <p className="error">Xato: {error}</p>;

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

export default UserList;

Uch qatorga e’tibor bering:

  1. const controller = new AbortController(); — effekt boshida;
  2. { signal: controller.signal }fetch ga uzatiladi;
  3. return () => controller.abort(); — tozalash funksiyasida.

err.name === "AbortError" tekshiruvi ham zarur. Bekor qilingan so’rov xato tashlaydi, lekin bu haqiqiy xato emas — uni ekranga chiqarish kerak emas.

Bog’liqlikka qarab qayta yuklash

Yuqoridagi kodda bog’liqliklar massivi [pageSize]. pageSize o’zgarganda ketma-ketlik shunday bo’ladi:

eski so'rov bekor qilinadi  →  yangi so'rov ketadi

Bu qidiruv maydoni bilan ishlaganda ayniqsa muhim: har harf uchun so’rov ketsa ham, faqat oxirgisining javobi ishlatiladi.

Bo’sh natija

Server muvaffaqiyatli javob qaytarsa ham ma’lumot bo’sh bo’lishi mumkin. Bu to’rtinchi holat:

if (isLoading) return <p>Yuklanmoqda...</p>;
if (error) return <p className="error">Xato: {error}</p>;
if (users.length === 0) return <p>Foydalanuvchi topilmadi.</p>;

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

Tartib muhim: avval isLoading, keyin error, so’ng bo’sh natija. Teskari tartibda yozsangiz, yuklanish paytida “topilmadi” chiqib qoladi — chunki users hali bo’sh massiv.

Shartli ko’rinish darsidagi ertaroq qaytarish naqshi aynan shu yerda ishlaydi.

Ma’lumot yuborish

Serverga yozish useEffect da emas, hodisa ishlovchisida bajariladi:

import { useState } from 'react';

function TaskForm() {
  const [title, setTitle] = useState("");
  const [isSending, setIsSending] = useState(false);
  const [error, setError] = useState(null);

  async function handleSubmit(e) {
    e.preventDefault();
    if (title.trim() === "") return;

    try {
      setIsSending(true);
      setError(null);

      const response = await fetch("https://jsonplaceholder.typicode.com/posts", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ title, completed: false }),
      });

      if (!response.ok) {
        throw new Error(`Server javobi: ${response.status}`);
      }

      setTitle("");
    } catch (err) {
      setError(err.message);
    } finally {
      setIsSending(false);
    }
  }

  return (
    <form onSubmit={handleSubmit}>
      <input
        type="text"
        value={title}
        onChange={(e) => setTitle(e.target.value)}
        placeholder="Vazifa nomi"
      />
      <button type="submit" disabled={isSending}>
        {isSending ? "Yuborilmoqda..." : "Qo'shish"}
      </button>
      {error && <p className="error">{error}</p>}
    </form>
  );
}

export default TaskForm;

disabled={isSending} ikki marta yuborishning oldini oladi. Tugma matni ham holatga qarab o’zgaradi — foydalanuvchi nimadir sodir bo’layotganini ko’radi.

useEffect darsidagi qoidani eslang: foydalanuvchi harakatidan kelib chiqadigan amal ishlovchida bajariladi, effektda emas.

Amaliy mashq

  1. UserList komponentini yozing va https://jsonplaceholder.typicode.com/users dan ro’yxat oling.
  2. Uchta holatni ham ko’rsating: yuklanmoqda, xato va natija.
  3. Manzilni ataylab buzing (masalan /userss) va xato xabari chiqishini tekshiring.
  4. response.ok tekshiruvini o’chiring, manzilni yana buzing va Unexpected token '<' xatosini o’z ko’zingiz bilan ko’ring. Keyin qaytaring.
  5. Brauzer konsolining tarmoq bo’limini oching va ishlab chiqishda nechta so’rov ketayotganini sanang.
  6. AbortController qo’shing va tozalash funksiyasida controller.abort() chaqiring.

4-qadam eng chalkash xato xabarining haqiqiy sababini ko’rsatadi: yozuvda JSON aytilgan, muammo esa serverning javobida.

Qisqacha xulosa

  • Har so’rov uchta holatga ega: yuklanmoqda, xato, tayyor — uchalasini ham ekranda qamrang.
  • useEffect ni async qilib bo’lmaydi; ichida async funksiya e’lon qilib chaqiring.
  • response.ok ni tekshiringfetch 404 va 500 ni xato deb hisoblamaydi.
  • finally blokida setIsLoading(false) yozing, aks holda xatoda ekran abadiy yuklanish holatida qoladi.
  • AbortController tozalash funksiyasida so’rovni bekor qiladi; AbortError ni xato sifatida ko’rsatmang.
  • StrictMode ishlab chiqishda ikkita so’rov yuboradi — bekor qilish shuning uchun ham kerak.
  • Ma’lumot yuborish hodisa ishlovchisida bajariladi, useEffect da emas; yuborish paytida tugmani disabled qiling.

Keyingi darsda holatni ko’tarish — bir necha komponent bitta ma’lumotni bo’lishishi.

Bu dars foydali bo'ldimi?

marta ko'rildi