Mundarija (23)
- Bu darsda
- 1. Nega bu kerak?
- 2. To'liq shakl
- 2.1 Uch holat
- 2.2 Haqiqiy fetch bilan
- 3. Kesh yo'q
- 3.1 Har qaytishda qayta yuklanadi
- 3.2 Bir xil ma'lumot — ikki so'rov
- 4. Sharshara (waterfall)
- 4.1 Ota yuklaydi, keyin bola
- 4.2 Parallel: ikkalasi birga
- 5. Yana uchta cheklov
- 6. Unda nima ishlatiladi
- 6.1 Effektdagi fetch qachon yetarli
- 7. Vazifalar kuzatuvi
- 8. Ko'p uchraydigan xatolar
- 9. Mashqlar
- 1-mashq (oson): muammoni nomlang
- 2-mashq (o'rta): xato holati
- 3-mashq (qiyin): sharsharani yo'qoting
- 10. Real ishda
- Xulosa
- Manbalar
Effektda ma'lumot olish: fetch + useEffect to'liq shakli va uning cheklovlari
Qisqacha:
useEffectichidafetchqilish ishlaydi, lekin to'g'ri yozish uchun ko'p narsa kerak: yuklanish, xato va ma'lumot holati,res.oktekshiruvi,AbortControllerbilan poygadan himoya. Shunda ham uchta muammo qoladi. Kesh yo'q — har qaytishda qayta yuklanadi. Sharshara (waterfall) — ota yuklab bo'lgach, bola so'rov boshlaydi: o'lchovda 0,56 s o'rniga 1,09 s. Server'da ishlamaydi — effekt faqat brauzerda bajariladi. Shuning uchun real ilovalarda ma'lumot olishni kutubxona (TanStack Query, SWR) yoki framework (Next.js, React Router) zimmasiga beradi. Effektdagifetch— o'rganish, kichik ilova va sodda holatlar uchun.
Bu darsda
fetch+useEffectning to'liq, to'g'ri shaklini yoza olasiz: uch holat, xato, bekor qilish.- Kesh yo'qligini so'rovlar hisobida ko'rasiz.
- Sharshara (waterfall) nima ekanini haqiqiy o'lchov bilan tushuntirasiz va
Promise.allbilan tezlashtirasiz. - Effektda ma'lumot olishning qolgan cheklovlarini (StrictMode, server, takror so'rov) sanab bera olasiz.
- Keyingi qismlarda ma'lumot olishni qaysi vositalar o'z zimmasiga olishini bilasiz.
Oldin bilishingiz kerak: useEffect III: cleanup va AbortController, Sizga effekt kerak emas, fetch asoslari, Promise kombinatorlari.
1. Nega bu kerak?
useEffect III darsida menyuni serverdan oldik va poygani AbortController bilan tuzatdik. Jasur aka xursand: "Endi butun menyu sahifasini shunday qilamiz — kategoriyalar, taom sahifasi, sharhlar." Sardor hisoblab chiqdi: har sahifada uchtadan state, try/catch, abort, "Yuklanmoqda…" va "Xato" matnlari. O'n sahifa — o'ttiz qator takror kod.
Keyin muammolar ko'rindi. Mehmon «Taom» dan «Ichimlik» ga o'tib, qaytdi — menyu yana "Yuklanmoqda…": hozirgina ko'rgan ro'yxat yana serverdan so'raldi. Taom sahifasi avval taomni yuklaydi, keyin sharhlarni — ketma-ket, ikki barobar sekin. Telefonda sahifa ochilganda bir soniya bo'sh oq ekran turadi.
Bu dars — effektdagi fetch ning to'liq shakli va halol bahosi. U qachon yetarli va qachon boshqa vosita kerak.
Hayotiy o'xshatish: oshxonada har buyurtma uchun bozorga borish. Ishlaydi — osh tayyor bo'ladi. Lekin sabzi bugun uchinchi marta kerak bo'lsa ham, har safar bozorga borasiz (kesh yo'q). Go'sht olib kelgandan keyingina guruch uchun yo'lga chiqasiz (sharshara). Restoranlarda buning uchun omborxona va ta'minotchi bor — kodda esa kutubxonalar.
2. To'liq shakl
2.1 Uch holat
Serverdan ma'lumot olayotgan komponent har doim uch holatdan birida: yuklanmoqda, xato yoki tayyor. Ularni bitta status state'ida saqlash qulay: uchta alohida boolean (isLoading, isError…) bir vaqtda true bo'lib qolishi mumkin edi (State strukturasini loyihalash darsidagi "imkonsiz holatlar").
Jonli blok vaqtga va internetga bog'liq bo'lmasligi uchun fetchDish — fetch ning kichik nusxasi: id 99 bo'lsa, server 404 qaytargandek xato beradi.
import { useEffect, useState } from "react";
const DISHES = { 1: { nom: "Osh", narx: 35000 } };
// fetch o'rnida: 150 ms dan keyin javob; yo'q id — 404 xatosi
function fetchDish(id, signal) {
return new Promise((resolve, reject) => {
const timer = setTimeout(() => {
if (DISHES[id]) resolve(DISHES[id]);
else reject(new Error(`404: taom ${id} topilmadi`));
}, 150);
signal.addEventListener("abort", () => {
clearTimeout(timer);
reject(signal.reason);
});
});
}
function Dish({ id }) {
const [status, setStatus] = useState("loading");
const [dish, setDish] = useState(null);
const [error, setError] = useState("");
useEffect(() => {
const controller = new AbortController();
setStatus("loading");
fetchDish(id, controller.signal)
.then((data) => {
setDish(data);
setStatus("ready");
})
.catch((err) => {
if (err.name === "AbortError") return;
setError(err.message);
setStatus("error");
});
return () => controller.abort();
}, [id]);
console.log("chizish:", id, status);
if (status === "loading") return <p>Yuklanmoqda…</p>;
if (status === "error") return <p role="alert">Xato: {error}</p>;
return <p>{dish.nom}: {dish.narx} so'm</p>;
}
function App() {
const [id, setId] = useState(1);
return (
<div>
<Dish id={id} />
<button onClick={() => setId(99)}>Taom 99</button>
</div>
);
}Konsolda:
chizish: 1 loading
chizish: 1 ready
chizish: 99 ready
chizish: 99 loading
chizish: 99 errorEkranda:
Xato: 404: taom 99 topilmadi
Taom 99Uch holat ham ko'rindi: avval yuklanish, keyin osh, «Taom 99» dan keyin yana yuklanish va xato. Xato matnida role="alert" — ekran o'quvchi (Malika) uni darhol o'qiydi.
Uchinchi qatorga qarang: chizish: 99 ready. id allaqachon 99, lekin status hali eski — ready, ekranda bir lahza osh turibdi. Effekt chizishdan keyin ishlaydi va setStatus("loading") faqat undan keyin keladi. Bu Sizga effekt kerak emas darsidagi "eskirgan oraliq holat" ning aynan o'zi.
| Render | Commit | Effekt | Cleanup |
|---|---|---|---|
1, loading |
"Yuklanmoqda…" | so'rov 1 | — |
1, ready |
osh | — | — |
«Taom 99»: 99, ready |
osh (eskirgan) | so'rov 99 | so'rov 1 abort (allaqachon tugagan) |
99, loading |
"Yuklanmoqda…" | — | — |
99, error |
xato matni | — | — |
Uchinchi qatorda cleanup oldin, keyin yangi effekt ishladi (useEffect III dagi tartib). Uni tuzatish uchun ham qo'shimcha kod kerak (masalan, ota'da key={id}).
2.2 Haqiqiy fetch bilan
fetchDish o'rniga haqiqiy fetch ikki qo'shimcha narsani talab qiladi: res.ok tekshiruvi (fetch 404 da xato tashlamaydi — fetch asoslari) va res.json():
import { useEffect, useState } from "react";
const API = "https://ilmhamroh.uz/api/mashq/menyu";
async function fetchDish(id, signal) {
const res = await fetch(`${API}/${id}`, { signal });
if (!res.ok) throw new Error(`${res.status}: taom ${id} topilmadi`);
return res.json();
}
function Dish({ id }) {
const [status, setStatus] = useState("loading");
const [dish, setDish] = useState(null);
const [error, setError] = useState("");
useEffect(() => {
const controller = new AbortController();
setStatus("loading");
fetchDish(id, controller.signal)
.then((data) => {
setDish(data);
setStatus("ready");
})
.catch((err) => {
if (err.name === "AbortError") return;
setError(err.message);
setStatus("error");
});
return () => controller.abort();
}, [id]);
if (status === "loading") return <p>Yuklanmoqda…</p>;
if (status === "error") return <p role="alert">Xato: {error}</p>;
return <p>{dish.nom}: {dish.narx} so'm</p>;
}
export default function App() {
return <Dish id={99} />;
}«Ishga tushir» bilan sinang: kurs serveri menyu/99 ga 404 qaytaradi va ekranda Xato: 404: taom 99 topilmadi chiqadi. id={1} qilsangiz — Osh: 35000 so'm.
Hisoblaymiz: bitta taomni ko'rsatish uchun 30 qatorga yaqin kod. Undan uchtasi state, to'qqiztasi effekt, uchtasi holatlar bo'yicha return. Har yangi sahifada — yana shuncha.
Tekshirib ko'ring:
.catchichidaif (err.name === "AbortError") return;qatorini olib tashlasak, nima bo'ladi? Qachon buni sezamiz?
Javob
id almashganda eski so'rov bekor qilinadi va uning catch i setStatus("error") qiladi. Ekranda bir lahza "Xato: signal is aborted without reason" chiqishi mumkin — yangi so'rovning "Yuklanmoqda…" si o'rnida. StrictMode'da esa bu birinchi ochilishdayoq ko'rinadi: sinov cleanup'i birinchi so'rovni bekor qiladi (Effekt hayot sikli).
3. Kesh yo'q
3.1 Har qaytishda qayta yuklanadi
Kategoriyalar orasida yurib, so'rovlarni sanaymiz. requests — modul o'zgaruvchisi, fetchMenu har chaqirilganda oshadi:
import { useEffect, useState } from "react";
let requests = 0;
const MENU = {
taom: ["Osh", "Lag'mon", "Manti"],
ichimlik: ["Ko'k choy"],
};
function fetchMenu(category) {
requests++;
console.log(`so'rov #${requests}: ${category}`);
return new Promise((resolve) => {
setTimeout(() => resolve(MENU[category]), 100);
});
}
function Menu({ category }) {
const [dishes, setDishes] = useState(null);
useEffect(() => {
let ignore = false;
setDishes(null); // yangi kategoriya — yana "Yuklanmoqda…"
fetchMenu(category).then((list) => {
if (!ignore) setDishes(list);
});
return () => {
ignore = true;
};
}, [category]);
if (dishes === null) return <p>Yuklanmoqda…</p>;
return <p>{dishes.join(", ")}</p>;
}
function App() {
const [category, setCategory] = useState("taom");
return (
<div>
<Menu category={category} />
<button onClick={() => setCategory("taom")}>Taom</button>{" "}
<button onClick={() => setCategory("ichimlik")}>
Ichimlik
</button>
</div>
);
}Konsolda:
so'rov #1: taom
so'rov #2: ichimlik
so'rov #3: taomEkranda:
Osh, Lag'mon, Manti
Taom IchimlikTaomlar ikki marta so'raldi. Ikkinchi marta ham mehmon "Yuklanmoqda…" ni ko'rdi, garchi ro'yxat bir necha soniya oldin ekranda bo'lgan bo'lsa ham. Komponentning state'i u bilan birga yo'qoladi yoki almashadi — eslab qolish uchun joy yo'q.
Kesh (cache) — oldin olingan javobni saqlab, keyingi safar darhol berish (Kesh strategiyalari brauzer va Service Worker darajasida bor, lekin React state'i undan bexabar). Kesh qo'shish — qo'lda yozilsa — yangi savollar tug'diradi. Qachon eskiradi? Server ma'lumoti o'zgarsa-chi? Ikki komponent bir xil narsani so'rasa — bitta so'rov bo'lsinmi? Bu "server holati" ning alohida dunyosi (Server state va client state).
3.2 Bir xil ma'lumot — ikki so'rov
Sahifa tepasidagi "Bugun 4 ta taom" hisoblagichi va pastdagi menyu ro'yxati bir xil ma'lumotga muhtoj. Har biri o'z effektida fetch qilsa — ikki bir xil so'rov. State'ni ota'ga ko'tarish (State'ni ko'tarish) yordam beradi, lekin komponentlar daraxtning turli chekkalarida bo'lsa, ma'lumotni pastga uzun props zanjiri bilan uzatish kerak bo'ladi.
4. Sharshara (waterfall)
4.1 Ota yuklaydi, keyin bola
App menyuni oladi, keyin birinchi taomni Dish ga beradi. Dish o'z effektida taom tafsilotini so'raydi. Lekin Dish faqat menyu kelgandan keyin chiziladi — demak uning effekti ham keyin boshlanadi. Kurs serverida har javob 500 ms ga sekinlashtirilgan (?kechikish=500):
import { useEffect, useState } from "react";
const API = "https://ilmhamroh.uz/api/mashq/menyu";
const start = performance.now();
const ms = () => Math.round(performance.now() - start);
function Dish({ id }) {
const [dish, setDish] = useState(null);
useEffect(() => {
console.log(`${ms()} ms: so'rov — taom ${id}`);
fetch(`${API}/${id}?kechikish=500`)
.then((res) => res.json())
.then((data) => {
console.log(`${ms()} ms: javob — taom ${id}`);
setDish(data);
});
}, [id]);
if (dish === null) return <p>Yuklanmoqda…</p>;
return <p>{dish.nom}: {dish.narx} so'm</p>;
}
function App() {
const [menu, setMenu] = useState(null);
useEffect(() => {
console.log(`${ms()} ms: so'rov — menyu`);
fetch(`${API}?kechikish=500`)
.then((res) => res.json())
.then((data) => {
console.log(`${ms()} ms: javob — menyu`);
setMenu(data);
});
}, []);
if (menu === null) return <p>Menyu yuklanmoqda…</p>;
return <Dish id={menu[0].id} />;
}Chrome 154 da uch marta o'lchadik (kod soddalik uchun abort'siz):
19 ms: so'rov — menyu
557 ms: javob — menyu
560 ms: so'rov — taom 1
1094 ms: javob — taom 1Qolgan ikki o'lchov: 1 087 va 1 092 ms. Ikkinchi so'rov birinchisi tugaguncha boshlanmadi — Dish hali yo'q edi. Sharshara (waterfall) — so'rovlar ketma-ket, har biri oldingisini kutadi. DevTools'ning Network panelida ular zinapoya kabi pastga tushadi — nomi shundan.
gantt
title So'rovlar vaqt bo'yicha (ms)
dateFormat x
axisFormat %L
section Sharshara
menyu :0, 557
taom 1 :560, 1094
section Parallel
menyu :0, 564
taom 1 :0, 564Diagrammaning yuqori qismi — sharshara: ikkinchi chiziq birinchisi tugagach boshlanadi. Pastki qism — keyingi bo'limdagi parallel usul.
4.2 Parallel: ikkalasi birga
Agar taom id si oldindan ma'lum bo'lsa (masalan, URL'dan: /menyu/1), ikkala so'rovni bitta effektda birga boshlash mumkin — Promise.all (Promise kombinatorlari):
import { useEffect, useState } from "react";
const API = "https://ilmhamroh.uz/api/mashq/menyu";
const start = performance.now();
const ms = () => Math.round(performance.now() - start);
const getJSON = (url) => fetch(url).then((res) => res.json());
function App() {
const [data, setData] = useState(null);
useEffect(() => {
console.log(`${ms()} ms: so'rov — menyu va taom 1 birga`);
Promise.all([
getJSON(`${API}?kechikish=500`),
getJSON(`${API}/1?kechikish=500`),
]).then(([menu, dish]) => {
console.log(`${ms()} ms: ikkala javob`);
setData({ menu, dish });
});
}, []);
if (data === null) return <p>Yuklanmoqda…</p>;
return <p>{data.dish.nom}: {data.dish.narx} so'm</p>;
}17 ms: so'rov — menyu va taom 1 birga
564 ms: ikkala javobUch o'lchov: 564, 564, 569 ms — sharsharadan deyarli ikki barobar tez. Lekin narxi bor: endi ma'lumot olish bola komponentdan ota'ga ko'chdi. Bola "nimaga muhtojman" ni o'zi aytmaydi — ota hammasini oldindan bilishi kerak. Komponentlar ko'payganda bu tez chalkashadi.
Framework'lar sharsharani boshqacha yechadi: ma'lumot komponent chizilishidan oldin, sahifa (marshrut) darajasida so'raladi. Masalan, router "loader" funksiyalari (React Router IV: data mode) va server komponentlari (Server Components).
5. Yana uchta cheklov
| Cheklov | Nima bo'ladi | Batafsil |
|---|---|---|
| StrictMode (dev) | har so'rov dev'da ikki marta yuboriladi (biri bekor) | Effekt hayot sikli |
| Server'da ishlamaydi | effekt faqat brauzerda — HTML bo'sh keladi, ma'lumot JS yuklangach | Next.js qismida |
| Takror kod | har komponentda uch state, abort, xato | Custom hooklar qisman yechadi |
Ikkinchi qator haqida. Server'da chiziladigan sahifa (SSR) uchun React komponentni serverda chaqiradi, lekin effektlarni ishlatmaydi — effekt "brauzer ekranni chizgandan keyin" degani, serverda esa ekran yo'q. Demak useEffect dagi fetch bilan qurilgan sahifa serverdan "Yuklanmoqda…" holatida keladi. Google uni shunday ko'radi, mehmon esa JavaScript yuklanguncha bo'sh sahifani ko'radi.
6. Unda nima ishlatiladi
Bu kursda keyingi qismlarda ma'lumot olishning to'rt yo'lini o'rganamiz. Hozir ularning nomini va qaysi muammoni hal qilishini bilish yetarli — kodini yozish shart emas:
| Vosita | Nima hal qiladi | Qayerda |
|---|---|---|
| TanStack Query (yoki SWR) — kutubxona | kesh, takror so'rovni birlashtirish, poyga, qayta urinish, eskirganini fonda yangilash | TanStack Query I |
| Router "loader" | sharshara: ma'lumot sahifa ochilishidan oldin, parallel | React Router IV |
use() + Suspense |
"Yuklanmoqda…" ni deklarativ ko'rsatish | Suspense, use() |
| Server komponentlar (Next.js) | ma'lumot serverda, HTML tayyor keladi | Server Components |
Ularning hammasi ichida bugungi darsdagi narsalar bor: AbortController, holatlar, xatolar. Farqi — siz ularni har komponentda qayta yozmaysiz.
Maslahat: React hujjati ham shuni tavsiya qiladi: framework ishlatsangiz — uning ma'lumot olish usulini; ishlatmasangiz — kesh qiladigan kutubxonani. Effektdagi
fetchni o'zingiz yozsangiz — bugungi «To'liq shakl» dagi hamma narsani unutmang.
6.1 Effektdagi fetch qachon yetarli
Halol bo'laylik: har doim ham kutubxona kerak emas.
- O'rganish va prototip — mexanizmni tushunish uchun bugungi kod eng yaxshi maktab.
- Bitta joyda, bitta so'rov — kesh ham, parallellik ham kerak bo'lmagan sahifa.
- Tashqi tizim bilan sinxronlash —
vazifalardagi server sinxroni aynan shunday: u "ma'lumot ko'rsatish" emas, "ikki nusxani moslashtirish". Bitta ro'yxat, bitta so'rov,AbortControllerbilan.
7. Vazifalar kuzatuvi
Bu dars vazifalar kodini o'zgartirmaydi. Kanondagi server effekti (useEffect III) — effektda ma'lumot olish. Uni bugungi ro'yxat bo'yicha tekshiramiz:
| Muammo | vazifalar da |
Nega |
|---|---|---|
| poyga | yo'q | AbortController — sinxronniTox |
| uch holat | bor | tarmoq: yuklanmoqda / xato / oflayn / tayyor |
| kesh | kerak emas | ro'yxat localStorage da, ekranda darhol |
| sharshara | yo'q | bitta so'rov (kalit bo'lmasa — keyin PUT) |
| StrictMode takrori | bor, zararsiz | birinchi GET bekor qilinadi |
| server'da chizish | kerak emas | SPA, statik hosting |
Qatorlarning ko'pi "yo'q" yoki "kerak emas" — kichik ilova uchun effekt yetarli. Uchinchi qatorga qarang: vazifalar "keshi" — localStorage. Sahifa ochilganda ro'yxat darhol ko'rinadi, server esa fonda solishtiriladi. Bu usulning nomi — "stale-while-revalidate" (eskisini ko'rsat, fonda yangila). TanStack Query'ning asosiy g'oyasi ham shu. TanStack Query qismida server holatini to'liq o'rganamiz.
8. Ko'p uchraydigan xatolar
| Belgi | Sabab | Davosi |
|---|---|---|
404 da "tayyor", ichida undefined |
fetch 404 da tashlamaydi |
if (!res.ok) throw … |
isLoading va isError birga true |
uchta boolean | bitta status |
| almashganda bir lahza eski ma'lumot | effekt chizishdan keyin | ota'da key, yoki kutubxona |
Xato: signal is aborted ekranda |
AbortError ajratilmagan |
if (err.name === "AbortError") return; |
| ikkinchi so'rov birinchisini kutadi | sharshara | parallel (Promise.all) yoki loader |
| qaytganda yana "Yuklanmoqda…" | kesh yo'q | kutubxona yoki yuqoriroqda saqlash |
9. Mashqlar
Mashqlar kurs/mashqlar/17/32-effektda-malumot/ da. Har yechimni «Ishga tushir» bilan sinang.
1-mashq (oson): muammoni nomlang
Har tavsifga muammo nomini yozing: poyga, sharshara yoki kesh.
- Taom sahifasi avval taomni, u kelgach — sharhlarni so'raydi:
- «Orqaga» bosilganda hozirgina ko'rilgan ro'yxat yana yuklanadi:
- Tez almashtirilganda eski kategoriyaning javobi yangisining ustiga yoziladi:
Yechim
Sharshara — so'rovlar ketma-ket, bittasi ikkinchisini kutadi. Kesh yo'qligi — olingan javob saqlanmaydi. Poyga — javoblar so'rovlar tartibida kelmaydi (useEffect III).
2-mashq (o'rta): xato holati
Reviews komponenti taom sharhlarini oladi, lekin faqat "tayyor" holatini biladi. Server xato bersa (bu blokda fetchReviews doim xato beradi), ekran abadiy "Yuklanmoqda…" da qoladi. Kodga status va error state'larini qo'shing: xatoda role="alert" li <p> da Sharhlar yuklanmadi: … chiqsin. Ishora: «Uch holat» bo'limidagi Dish.
import { useEffect, useState } from "react";
function fetchReviews(dishId) {
return new Promise((resolve, reject) => {
setTimeout(() => reject(new Error("500: server xatosi")), 100);
});
}
function Reviews({ dishId }) {
const [reviews, setReviews] = useState(null);
useEffect(() => {
let ignore = false;
fetchReviews(dishId).then((list) => {
if (!ignore) setReviews(list);
});
return () => {
ignore = true;
};
}, [dishId]);
if (reviews === null) return <p>Yuklanmoqda…</p>;
return <p>{reviews.length} ta sharh</p>;
}
function App() {
return <Reviews dishId={1} />;
}Sayt oynasida (Chrome 154 da tekshirildi):
Konsol: Uncaught (in promise) Error: 500: server xatosi
Ekran: Yuklanmoqda…Yechim
import { useEffect, useState } from "react";
function fetchReviews(dishId) {
return new Promise((resolve, reject) => {
setTimeout(() => reject(new Error("500: server xatosi")), 100);
});
}
function Reviews({ dishId }) {
const [status, setStatus] = useState("loading");
const [reviews, setReviews] = useState([]);
const [error, setError] = useState("");
useEffect(() => {
let ignore = false;
setStatus("loading");
fetchReviews(dishId)
.then((list) => {
if (ignore) return;
setReviews(list);
setStatus("ready");
})
.catch((err) => {
if (ignore) return;
setError(err.message);
setStatus("error");
});
return () => {
ignore = true;
};
}, [dishId]);
if (status === "loading") return <p>Yuklanmoqda…</p>;
if (status === "error") {
return <p role="alert">Sharhlar yuklanmadi: {error}</p>;
}
return <p>{reviews.length} ta sharh</p>;
}
function App() {
return <Reviews dishId={1} />;
}Ekranda:
Sharhlar yuklanmadi: 500: server xatosiKonsol toza: xato catch da ushlandi. Birinchi variantdagi Uncaught (in promise) — ushlanmagan rad etilgan Promise (async/await). Effektdagi har fetch zanjiri .catch bilan tugashi shart.
3-mashq (qiyin): sharsharani yo'qoting
App menyuni, Dish esa taomni oladi — sharshara. Konsoldagi "qadam" lar so'rovlar tartibini ko'rsatadi. Kodni o'zgartiring: ikkala so'rov bitta effektda, Promise.all bilan birga boshlansin (taom id si — 1, oldindan ma'lum). Dish endi ma'lumotni props'dan olsin va o'zi so'rov yubormasin. Konsolda ikki so'rov ketma-ket boshlanib, keyin javoblar kelsin.
import { useEffect, useState } from "react";
function fakeFetch(name, data) {
console.log("so'rov:", name);
return new Promise((resolve) => {
setTimeout(() => {
console.log("javob:", name);
resolve(data);
}, 100);
});
}
function Dish({ id }) {
const [dish, setDish] = useState(null);
useEffect(() => {
fakeFetch(`taom ${id}`, { nom: "Osh" }).then(setDish);
}, [id]);
return <p>{dish ? dish.nom : "…"}</p>;
}
function App() {
const [menu, setMenu] = useState(null);
useEffect(() => {
fakeFetch("menyu", [{ id: 1 }, { id: 4 }]).then(setMenu);
}, []);
if (menu === null) return <p>Menyu…</p>;
return <Dish id={menu[0].id} />;
}Konsolda:
so'rov: menyu
javob: menyu
so'rov: taom 1
javob: taom 1Yechim
import { useEffect, useState } from "react";
function fakeFetch(name, data) {
console.log("so'rov:", name);
return new Promise((resolve) => {
setTimeout(() => {
console.log("javob:", name);
resolve(data);
}, 100);
});
}
function Dish({ dish }) {
return <p>{dish.nom}</p>;
}
function App() {
const [data, setData] = useState(null);
useEffect(() => {
let ignore = false;
Promise.all([
fakeFetch("menyu", [{ id: 1 }, { id: 4 }]),
fakeFetch("taom 1", { nom: "Osh" }),
]).then(([menu, dish]) => {
if (!ignore) setData({ menu, dish });
});
return () => {
ignore = true;
};
}, []);
if (data === null) return <p>Menyu…</p>;
return <Dish dish={data.dish} />;
}Konsolda:
so'rov: menyu
so'rov: taom 1
javob: menyu
javob: taom 1Ekranda:
OshIkkala so'rov birga boshlandi: umumiy vaqt — eng sekin javobniki (bu yerda 100 ms), yig'indisi emas (200 ms). Dish endi oddiy, "toza" komponent — faqat props. Lekin endi App Dish qanday ma'lumotga muhtojligini bilishi kerak. Katta ilovada bu bog'liqlikni router loader'lari yoki server komponentlar boshqaradi.
10. Real ishda
- Ko'p ishlab chiqarish (production) loyihalarida
useEffectichida to'g'ridan-to'g'rifetchdeyarli uchramaydi: TanStack Query yoki framework'ning ma'lumot olish usuli ishlatiladi. Lekin intervyuda va eski kodda bu naqsh har doim bor — uni o'qiy olish va kamchiliklarini aytib berish majburiy. - Network panelidagi sharshara — sahifa sekinligining birinchi sababi. Lighthouse va Web Vitals'dagi LCP (eng katta element qachon chizildi) ko'pincha shundan yomonlashadi.
res.oktekshiruvi vaAbortErrorni ajratish — kutubxona ishlatsangiz ham kerak bo'ladigan odatlar (API klient qatlami).- Intervyu savollari: "useEffect'da fetch qilishning kamchiliklari?", "waterfall nima va qanday oldini olasiz?", "nega TanStack Query kerak, oddiy fetch yetmaydimi?".
Xulosa
- To'liq shakl: bitta
status(loading / error / ready),res.oktekshiruvi,.catch,AbortControllervaAbortErrorni ajratish. - Kesh yo'q: qaytishda qayta yuklanadi, bir xil ma'lumot — bir necha so'rov.
- Sharshara: bola so'rovi ota javobini kutadi. O'lchov: 1,09 s o'rniga parallel 0,56 s (
Promise.all). - Effekt serverda ishlamaydi, StrictMode dev'da ikki so'rov yuboradi, har komponentda takror kod.
- Real ilovada — kutubxona (TanStack Query, SWR) yoki framework (router loader, server komponentlar); effektdagi
fetch— o'rganish, kichik ilova va sinxronlash uchun.
Keyingi dars: useRef I: render chaqirmaydigan xotira — o'zgarganda qayta chizilmaydigan quti: taymer id, oldingi qiymat va ref bilan state farqi.
Manbalar
- React: "Synchronizing with Effects" — "What are good alternatives to data fetching in Effects?" — react.dev/learn/synchronizing-with-effects
- React: "You Might Not Need an Effect" — "Fetching data" — react.dev/learn/you-might-not-need-an-effect
- MDN:
Response.ok,AbortController— developer.mozilla.org/docs/Web/API
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!