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:
const controller = new AbortController();— effekt boshida;{ signal: controller.signal }—fetchga uzatiladi;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
UserListkomponentini yozing vahttps://jsonplaceholder.typicode.com/usersdan ro’yxat oling.- Uchta holatni ham ko’rsating: yuklanmoqda, xato va natija.
- Manzilni ataylab buzing (masalan
/userss) va xato xabari chiqishini tekshiring. response.oktekshiruvini o’chiring, manzilni yana buzing vaUnexpected token '<'xatosini o’z ko’zingiz bilan ko’ring. Keyin qaytaring.- Brauzer konsolining tarmoq bo’limini oching va ishlab chiqishda nechta so’rov ketayotganini sanang.
AbortControllerqo’shing va tozalash funksiyasidacontroller.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.
useEffectniasyncqilib bo’lmaydi; ichidaasyncfunksiya e’lon qilib chaqiring.response.okni tekshiring —fetch404va500ni xato deb hisoblamaydi.finallyblokidasetIsLoading(false)yozing, aks holda xatoda ekran abadiy yuklanish holatida qoladi.AbortControllertozalash funksiyasida so’rovni bekor qiladi;AbortErrorni xato sifatida ko’rsatmang.StrictModeishlab chiqishda ikkita so’rov yuboradi — bekor qilish shuning uchun ham kerak.- Ma’lumot yuborish hodisa ishlovchisida bajariladi,
useEffectda emas; yuborish paytida tugmanidisabledqiling.
Keyingi darsda holatni ko’tarish — bir necha komponent bitta ma’lumotni bo’lishishi.