useEffect — asinxron funksiya, fetch bilan ishlash
To'liq fetch pattern
Server dan ma'lumot olish — eng ko'p uchraydigan useEffect ishlatilishi. Lekin to'g'ri yozish uchun uchta holatni boshqarish kerak: yuklanmoqda, xato, muvaffaqiyat.
function UserRoyxati() {
const [users, setUsers] = useState([]);
const [yuklanmoqda, setYuklanmoqda] = useState(true);
const [xato, setXato] = useState(null);
useEffect(() => {
async function olish() {
try {
setYuklanmoqda(true);
setXato(null);
const res = await fetch('https://jsonplaceholder.typicode.com/users');
if (!res.ok) {
throw new Error(`Server xatosi: ${res.status}`);
}
const data = await res.json();
setUsers(data);
} catch (err) {
setXato(err.message);
} finally {
setYuklanmoqda(false);
}
}
olish();
}, []);
if (yuklanmoqda) return <p>Yuklanmoqda...</p>;
if (xato) return <p>Xato: {xato}</p>;
return (
<ul>
{users.map(u => <li key={u.id}>{u.name}</li>)}
</ul>
);
}
Uchta holat:
yuklanmoqda = true → "Yuklanmoqda..." ko'rsatiladi
xato = "..." → xato xabari ko'rsatiladi
muvaffaqiyat → ma'lumot ko'rsatiladi
Parametrga bog'liq so'rov
Qidiruv, filtr, sahifa raqami — bular o'zgarganda yangi so'rov yuborilishi kerak.
function MahsulotQidirish() {
const [qidiruv, setQidiruv] = useState('');
const [mahsulotlar, setMahsulotlar] = useState([]);
const [yuklanmoqda, setYuklanmoqda] = useState(false);
useEffect(() => {
if (!qidiruv.trim()) {
setMahsulotlar([]);
return;
}
const controller = new AbortController();
async function qidirish() {
setYuklanmoqda(true);
try {
const res = await fetch(
`/api/mahsulotlar?q=${qidiruv}`,
{ signal: controller.signal }
);
const data = await res.json();
setMahsulotlar(data);
} catch (err) {
if (err.name !== 'AbortError') setMahsulotlar([]);
} finally {
setYuklanmoqda(false);
}
}
qidirish();
return () => controller.abort();
}, [qidiruv]); // qidiruv o'zgarganda qayta so'rov
return (
<div>
<input
value={qidiruv}
onChange={e => setQidiruv(e.target.value)}
placeholder="Qidirish..."
/>
{yuklanmoqda && <p>Qidirilmoqda...</p>}
<ul>
{mahsulotlar.map(m => <li key={m.id}>{m.nomi}</li>)}
</ul>
</div>
);
}
Foydalanuvchi har harf yozganda so'rov ketadi. AbortController eski so'rovni bekor qiladi — faqat oxirgi so'rovning natijasi ko'rsatiladi.
Race condition muammosi
Foydalanuvchi tez-tez filtr o'zgartirsa — bir nechta so'rov ketadi. Qaysi biri oxirgi kelishini bilmaysiz.
So'rov 1 (id=1) → ketdi...
So'rov 2 (id=2) → ketdi...
So'rov 2 → keldi, setUser(user2) ✅
So'rov 1 → keldi, setUser(user1) ❌ — eski ma'lumot ustiga yozdi!
AbortController bu muammoni hal qiladi — dependency o'zgarganda cleanup ishlaydi va eski so'rov bekor qilinadi.
userId = 1 → so'rov boshlandi
userId = 2 → cleanup: so'rov 1 bekor qilindi
→ yangi so'rov boshlandi
Tez-tez uchraydigan xatolar
res.ok ni tekshirmaslik:
// ❌ 404, 500 xatolarda ham data olishga urinadi
const data = await fetch('/api/users').then(r => r.json());
// ✅ Status tekshiriladi
const res = await fetch('/api/users');
if (!res.ok) throw new Error(`${res.status}`);
const data = await res.json();
fetch faqat tarmoq xatosida (internet yo'q) reject qiladi. Server 404 yoki 500 qaytarsa — Promise resolve bo'ladi. res.ok tekshirilmasa — xato sezilmaydi.
Loading state ni boshida false qoldirish:
// ❌ Birinchi render da ma'lumot yo'q, loading ham yo'q
// → bo'sh sahifa ko'rsatiladi
const [yuklanmoqda, setYuklanmoqda] = useState(false);
// ✅ Boshida true — darhol "Yuklanmoqda..." ko'rsatiladi
const [yuklanmoqda, setYuklanmoqda] = useState(true);
Xulosa
useEffect ichida fetch:
1. async funksiya ichida yozing
2. try/catch/finally — uch holat
3. res.ok tekshiring
4. AbortController — cleanup da bekor qiling
5. dependency array to'g'ri to'ldiring
Bu pattern ko'p takrorlanadi. Keyinchalik TanStack Query bu ishni avtomatik qiladi — loading, error, caching, refetch hammasi tayyor. Lekin asosini tushunish muhim.
Keyingi dars
13-dars: useRef — DOM ga murojaat, focus, scroll