Mundarija (25)
- Bu darsda
- 1. Nega bu kerak?
- 2. Uch shakl — yonma-yon
- 3. React qanday solishtiradi
- 3.1 Object.is — har element alohida
- 3.2 Komponent ichidagi obyekt — har chizishda yangi
- 3.3 Uchta davo
- 4. Funksiya bog'liqligi
- 4.1 Funksiya ham obyekt
- 4.2 Davolar
- 4.3 Barqaror qiymatlar — massivga shart emas
- 5. ESLint exhaustive-deps
- 5.1 Qoida nimani tekshiradi
- 5.2 Massivni "aldash" — eskirgan closure
- 5.3 Bog'liqlikni halol kamaytirish
- 6. Vazifalar qadami: kanondagi massivlar
- 7. Ko'p uchraydigan xatolar
- 8. Mashqlar
- 1-mashq (oson): effekt qayta ishlaydimi?
- 2-mashq (o'rta): tab nomini tuzating
- 3-mashq (qiyin): obyekt prop'dan keladi
- 4-mashq: Vazifalar qadami
- 9. Real ishda
- Xulosa
- Manbalar
useEffect II: dependency massivi chuqur — Object.is, obyekt va funksiya bog'liqliklari
Qisqacha: Har chizishdan keyin React bog'liqliklar massividagi har qiymatni oldingi chizishdagisi bilan
Object.isorqali solishtiradi. Birortasi farq qilsa — effekt qayta ishlaydi. Son va satr qiymati bo'yicha solishtiriladi. Komponent ichida yaratilgan obyekt, massiv va funksiya esa har chizishda yangi, shuning uchun ular massivda tursa, effekt har safar ishlaydi. Davosi: massivga primitiv maydonni yozish yoki obyektni effekt ichida yaratish. Massiv — sizning tanlovingiz emas, effekt ishlatgan reaktiv qiymatlar ro'yxati. ESLintexhaustive-depsuni tekshiradi; massivdan qiymatni olib tashlab "aldash" effektni eskirgan qiymat bilan qoldiradi.
Bu darsda
- Massivning uch shaklini konsolda taqqoslaysiz va qaysi biri qachon kerakligini aytasiz.
- React massivni
Object.isbilan qanday solishtirishini tushuntira olasiz. - Obyekt va funksiya bog'liqligi nega effektni har chizishda ishga tushirishini ko'rasiz va uch usulda tuzatasiz.
- ESLint
exhaustive-depsxabarlarini o'qiysiz va ularga ko'r-ko'rona emas, o'ylab javob berasiz. - Massivni "aldash" nima bilan tugashini jonli ko'rasiz.
Oldin bilishingiz kerak: useEffect I, Tenglik: ==, === va Object.is, Closure tuzoqlari, State II: snapshot va updater funksiya.
1. Nega bu kerak?
Oldingi darsda effektni yozdik va massivga "effekt ishlatgan qiymatlar" ni qo'yishni o'rgandik. Bir qarashda oddiy qoida. Lekin Sardor ikki kunda ikki xil muammoga duch keldi.
Birinchi kuni u menyu filtrini obyektga yig'di: const filter = { category, limit: 10 } va [filter] deb yozdi. Konsolga qarasa — effekt har chizishda ishlayapti, hech narsa o'zgarmasa ham. Hatto mutlaqo boshqa tugmani bosganda ham.
Ikkinchi kuni u "ortiqcha ishlamasin" deb massivni bo'shatdi: []. Endi effekt bir marta ishladi — va kategoriya almashganda tab nomi eski qoldi. ESLint sariq chiziq chizdi, Sardor uni // eslint-disable-next-line bilan o'chirdi.
Ikkala muammoning ildizi bitta: massiv qanday ishlashini aniq bilmaslik. Bugun shu "qora quti" ni ochamiz. Hayotiy o'xshatish: oshxonada buyurtma qog'ozi. Oshpaz yangi taom tayyorlashdan oldin qog'ozdagi har qatorni avvalgisi bilan solishtiradi. Bitta qator farq qilsa — qaytadan pishiradi. Lekin ofitsiant har safar xuddi shu buyurtmani yangi qog'ozga qayta yozib kelsa, va oshpaz qog'ozning o'ziga qarasa (matniga emas) — u har safar "yangi buyurtma" deb o'ylaydi.
2. Uch shakl — yonma-yon
Bitta komponentda uchta effekt: massivsiz, bo'sh massivli va [category] li. Tugmalar kategoriyani tanlaydi va bosishlar sonini oshiradi. Blok uch marta bosadi: «Taom» (o'sha kategoriya), «Ichimlik», yana «Ichimlik».
import { useEffect, useState } from "react";
function App() {
const [category, setCategory] = useState("taom");
const [clicks, setClicks] = useState(0);
useEffect(() => {
console.log("A (massivsiz):", category);
});
useEffect(() => {
console.log("B ([]):", category);
}, []);
useEffect(() => {
console.log("C ([category]):", category);
}, [category]);
function choose(next) {
setCategory(next);
setClicks(clicks + 1);
}
return (
<div>
<p>{category}, bosildi: {clicks}</p>
<button onClick={() => choose("taom")}>Taom</button>{" "}
<button onClick={() => choose("ichimlik")}>Ichimlik</button>
</div>
);
}Konsolda:
A (massivsiz): taom
B ([]): taom
C ([category]): taom
A (massivsiz): taom
A (massivsiz): ichimlik
C ([category]): ichimlik
A (massivsiz): ichimlikEkranda:
ichimlik, bosildi: 3
Taom IchimlikTo'rt chizish bo'ldi: ochilish va uch bosish. Har birida qaysi effekt ishladi:
Chizish (category) |
A (massivsiz) | B ([]) |
C ([category]) |
|---|---|---|---|
| ochilish (taom) | |||
| «Taom» (taom) | — | — (o'sha) | |
| «Ichimlik» (ichimlik) | — | ||
| «Ichimlik» (ichimlik) | — | — (o'sha) |
- A — har chizishda.
clickso'zgargani ham yetarli edi. - B — faqat birinchi chizishda. Uning
categorysi abadiy"taom"bo'lib qoldi. - C —
categoryhaqiqatan o'zgargandagina.
Effekt ham bir xil sondagi chizishlardan keyin bajariladi — farq faqat massivda. React effektlarni yozilgan tartibda ishlatadi: A, B, C.
Tekshirib ko'ring: Jadvalning ikkinchi qatorida «Taom» bosildi, lekin
categoryo'zgarmadi. Unda nega chizish bo'ldi va A ishladi?
Javob
Chunki clicks o'zgardi (0 → 1). Bitta ishlovchida ikkita set… chaqirildi — React ularni bitta chizishga birlashtirdi (batching). Chizish bo'ldi — massivsiz A ishladi. C esa category ni solishtirdi: "taom" va "taom" — bir xil, o'tkazib yuborildi.
3. React qanday solishtiradi
3.1 Object.is — har element alohida
Massivni React butunligicha solishtirmaydi. U har elementni oldingi chizishdagi o'sha o'rindagi element bilan Object.is orqali taqqoslaydi (Tenglik darsidan tanish). Hech bo'lmasa bittasi false bersa — effekt ishlaydi.
flowchart TD
S["Chizish tugadi, commit bo'ldi"] --> M{"Massiv bormi?"}
M -- "yo'q" --> RUN["Effekt ishlaydi"]
M -- "ha" --> F{"Birinchi chizishmi?"}
F -- "ha" --> RUN
F -- "yo'q" --> C{"Har element: Object.is(eski, yangi)"}
C -- "biri false" --> RUN
C -- "hammasi true" --> SKIP["O'tkazib yuboriladi"]Diagrammadagi pastki romb — butun sirning kaliti. Object.is qanday javob berishini eslaymiz:
console.log(Object.is("taom", "taom")); // true
console.log(Object.is(35000, 35000)); // true
console.log(Object.is({ dish: "osh" }, { dish: "osh" })); // false
const filter = { category: "taom" };
console.log(Object.is(filter, filter)); // true
console.log(Object.is(() => 1, () => 1)); // false
console.log(Object.is(NaN, NaN), NaN === NaN); // true falseSon va satr — qiymati bo'yicha. Obyekt, massiv va funksiya — havolasi bo'yicha: ichi bir xil ikki obyekt — baribir ikki xil obyekt. Bitta obyektning o'zi — o'ziga teng. NaN — Object.is uchun o'ziga teng (=== uchun emas). Shu sababli React === emas, aynan Object.is ni tanlagan: NaN li bog'liqlik har chizishda "o'zgardi" deyilmaydi.
3.2 Komponent ichidagi obyekt — har chizishda yangi
Endi Sardorning birinchi muammosi. Filtr obyekti komponent ichida yaratiladi. Blok +1 ni ikki marta bosadi — kategoriya o'zgarmaydi:
import { useEffect, useState } from "react";
function App() {
const [category] = useState("taom");
const [n, setN] = useState(0);
const filter = { category, limit: 10 }; // har chizishda YANGI
useEffect(() => {
console.log("effekt: filtr", filter.category);
}, [filter]);
return <button onClick={() => setN(n + 1)}>+1</button>;
}Konsolda:
effekt: filtr taom
effekt: filtr taom
effekt: filtr taomUch chizish — uch effekt, garchi category hech qachon o'zgarmagan bo'lsa ham. Sabab: komponent har chizishda boshidan chaqiriladi va const filter = { … } qatori har safar yangi obyekt yaratadi. React Object.is(eskiFilter, yangiFilter) ni tekshiradi — false. U uchun bu "yangi qog'ozdagi buyurtma".
Bu yerda effekt faqat konsolga yozyapti — zarari yo'q. Lekin effekt serverga so'rov yuborsa yoki chat'ga ulansa, har bosishda yangi so'rov va qayta ulanish. Agar effekt ichida state o'zgarsa — cheksiz sikl.
3.3 Uchta davo
1. Primitiv maydonni massivga yozing. Effektga butun obyekt emas, uning category maydoni kerak edi:
import { useEffect, useState } from "react";
function App() {
const [category] = useState("taom");
const [n, setN] = useState(0);
const filter = { category, limit: 10 };
const filterCategory = filter.category; // satr — qiymati bilan
useEffect(() => {
console.log("effekt: filtr", filterCategory);
}, [filterCategory]);
return <button onClick={() => setN(n + 1)}>+1</button>;
}Konsolda:
effekt: filtr taom2. Obyektni effekt ichida yarating. Obyekt faqat effektga kerak bo'lsa, uni effektning o'zida yasang — massivda faqat uning "xom ashyosi" qoladi:
useEffect(() => {
const filter = { category, limit: 10 }; // effekt ichida
console.log("effekt: filtr", filter.category);
}, [category]);3. O'zgarmas narsani komponentdan tashqariga chiqaring. limit: 10 hech qachon o'zgarmaydi — u komponentning har chizishiga bog'liq emas. Modul darajasidagi const LIMIT = 10 — har doim o'sha qiymat, massivga yozish ham shart emas.
Maslahat: Obyektni har chizishda bir xil havola bilan saqlab turuvchi
useMemohooki ham bor (memo, useMemo, useCallback darsida). Lekin u effekt muammosining birinchi davosi emas. Avval yuqoridagi uch usulni sinang — ular sodda va ko'pincha yetarli.
4. Funksiya bog'liqligi
4.1 Funksiya ham obyekt
Funksiya ham JavaScript'da obyekt (Funksiya — qiymat). Komponent ichida e'lon qilingan funksiya har chizishda yangidan yaratiladi:
import { useEffect, useState } from "react";
function App() {
const [category] = useState("taom");
const [n, setN] = useState(0);
function buildTitle() {
return `Bahor — ${category}`;
}
useEffect(() => {
document.title = buildTitle();
console.log("sarlavha:", document.title);
}, [buildTitle]);
return <button onClick={() => setN(n + 1)}>+1</button>;
}Konsolda:
sarlavha: Bahor — taom
sarlavha: Bahor — taom
sarlavha: Bahor — taomXuddi obyekt kabi: uch chizish — uch effekt. buildTitle har safar yangi funksiya.
4.2 Davolar
Uchala davo funksiyaga ham to'g'ri keladi:
- Effekt ichiga ko'chiring. Funksiya faqat effektda ishlatilsa — u effektning ichida yashasin. Massivda esa u o'qiydigan qiymat (
category) qoladi. - Komponentdan tashqariga chiqaring. Funksiya props va state'ni ishlatmasa (
formatPrice(n)kabi), uni komponentdan tashqarida e'lon qiling — u bitta, o'zgarmas. useCallback— funksiyani chizishlar orasida saqlab turuvchi hook (memo, useMemo, useCallback darsida).
Birinchi davo bilan:
import { useEffect, useState } from "react";
function App() {
const [category] = useState("taom");
const [n, setN] = useState(0);
useEffect(() => {
function buildTitle() {
return `Bahor — ${category}`;
}
document.title = buildTitle();
console.log("sarlavha:", document.title);
}, [category]);
return <button onClick={() => setN(n + 1)}>+1</button>;
}Konsolda:
sarlavha: Bahor — taom4.3 Barqaror qiymatlar — massivga shart emas
Ba'zi qiymatlar komponent ichida bo'lsa ham, React ularni har chizishda bir xil qilib beradi:
useStatedan qaytgan set funksiyasi (setCount) — doim o'sha funksiya;useRefqaytargan obyekt (useRef I darsida).
ESLint ularni taniydi va massivga yozishni talab qilmaydi. Yozsangiz ham zarari yo'q — ular hech qachon "o'zgarmaydi".
Reaktiv qiymat (reactive value) — chizishdan chizishga o'zgarishi mumkin bo'lgan qiymat: props, state va komponent ichida ulardan hisoblangan har narsa (obyekt va funksiyalar ham). Massiv — aynan effekt ishlatgan reaktiv qiymatlar ro'yxati. Komponentdan tashqaridagi const va barqaror set funksiyalari reaktiv emas.
Tekshirib ko'ring:
const LIMIT = 10;komponentdan tashqarida. Effekt ichidaLIMITishlatilsa, uni massivga yozish kerakmi?const limit = 10;komponent ichida bo'lsa-chi?
Javob
Tashqaridagi LIMIT — yo'q: u modul yuklanganda bir marta yaratiladi va hech qachon o'zgarmaydi. ESLint ham so'ramaydi. Ichidagi limit = 10 — rasman reaktiv qiymat (komponent ichida), lekin son har safar 10. Object.is(10, 10) — true, massivda tursa ham effektni qayta ishga tushirmaydi. Toza yo'l — uni tashqariga chiqarish: o'zgarmas narsa komponentga tegishli emas.
5. ESLint exhaustive-deps
5.1 Qoida nimani tekshiradi
eslint-plugin-react-hooks ning ikkinchi qoidasi — exhaustive-deps ("to'liq bog'liqliklar"). U effekt ichida ishlatilgan har reaktiv qiymatni topadi va massivda bor-yo'qligini tekshiradi. Sardorning ikki kunlik xatolarini bitta faylga yig'dik:
import { useEffect, useState } from "react";
export function MenuTitle({ category }) {
const [count, setCount] = useState(0);
const filter = { category, limit: 10 };
function buildTitle() {
return `Bahor — ${category}`;
}
useEffect(() => {
document.title = buildTitle();
}, [buildTitle]);
useEffect(() => {
console.log("filtr:", filter.category);
}, [filter]);
useEffect(() => {
document.title = `${category}: ${count}`;
}, []);
return <button onClick={() => setCount(count + 1)}>{count}</button>;
}ESLint 10.12.0 va plagin 7.1.1 (qoida nomi qisqartirildi):
5:9 warning The 'filter' object makes the dependencies of useEffect Hook (at line 14) change on every render. Move it inside the useEffect callback. Alternatively, wrap the initialization of 'filter' in its own useMemo() Hook
6:3 warning The 'buildTitle' function makes the dependencies of useEffect Hook (at line 11) change on every render. Move it inside the useEffect callback. Alternatively, wrap the definition of 'buildTitle' in its own useCallback() Hook
17:6 warning React Hook useEffect has missing dependencies: 'category' and 'count'. Either include them or remove the dependency array
✖ 3 problems (0 errors, 3 warnings)Tarjimasi:
- 5-qator: "
filterobyektiuseEffecthookining (14-qator) bog'liqliklarini har chizishda o'zgartiradi. UniuseEffectichiga ko'chiring yokiuseMemoga o'rang." Aynan «Uchta davo» bo'limidagi ikkinchi davo. - 6-qator: xuddi shunday,
buildTitlefunksiyasi uchun; muqobili —useCallback. - 17-qator: "
useEffectda bog'liqliklar yetishmayapti:categoryvacount. Ularni qo'shing yoki massivni olib tashlang."
E'tibor bering: hammasi warning (sariq), error emas. Kod ishlaydi — faqat noto'g'ri ishlaydi.
5.2 Massivni "aldash" — eskirgan closure
Uchinchi xabar Sardorning ikkinchi kuni. U [] yozdi, chunki effekt "bir marta ishlasin" demoqchi edi. Natija jonli: «Ichimlik» bosiladi, lekin tab nomi qotib qoladi. Ikkinchi effekt (massivsiz) har chizishdan keyin hozirgi tab nomini konsolga yozadi:
import { useEffect, useState } from "react";
function App() {
const [category, setCategory] = useState("taom");
useEffect(() => {
document.title = `Bahor — ${category}`;
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []); // ❌ "aldash": category ishlatiladi, lekin massivda yo'q
useEffect(() => {
console.log(`ekranda: ${category}, tabda: ${document.title}`);
});
return (
<button onClick={() => setCategory("ichimlik")}>Ichimlik</button>
);
}Konsolda:
ekranda: taom, tabda: Bahor — taom
ekranda: ichimlik, tabda: Bahor — taomEkranda — ichimlik, tabda — hali ham taom. Bosqichlar bo'yicha:
| Render | Commit | Effekt | Cleanup |
|---|---|---|---|
ochilish: taom |
<button> DOM'ga |
1-effekt: tab = taom; 2-effekt: log | — |
«Ichimlik»: ichimlik |
matn o'sha | 1-effekt o'tkazildi ([]); 2-effekt: log |
— |
Jadvalning ikkinchi qatori — muammoning o'zi: render yangi, 1-effekt esa massivi bo'sh bo'lgani uchun umuman ishga tushmadi. Effekt birinchi chizishning category sini closure orqali ushlab qoldi va boshqa hech qachon ishlamadi (Closure tuzoqlari — eskirgan closure (stale closure)). Hech qanday xato yo'q, konsol toza — ESLint ogohlantirishi esa izoh bilan o'chirilgan. Bunday xatoni production'da mijoz topadi.
Massivni aldash — effekt ishlatgan reaktiv qiymatni massivdan ataylab chiqarish. U "effekt kamroq ishlasin" degan istakdan tug'iladi. Lekin massiv istak emas, fakt: "effekt shu qiymatlarga bog'liq". Effekt kamroq ishlashini istasangiz, massivni emas, kodni o'zgartiring — effekt kamroq qiymatga bog'liq bo'lsin.
5.3 Bog'liqlikni halol kamaytirish
Massivni qisqartirishning halol yo'llari:
| Holat | Yo'l |
|---|---|
| obyekt yoki funksiya faqat effektda kerak | effekt ichiga ko'chiring |
| props/state ishlatmaydigan yordamchi | komponentdan tashqariga |
setCount(count + 1) — count faqat yangilash uchun |
updater: setCount((c) => c + 1) (State II) |
| eng so'nggi qiymatni o'qish kerak, lekin qayta ishga tushish kerak emas | useEffectEvent (useEffectEvent darsida) |
| hisoblanadigan qiymat effektda | effekt umuman kerak emas (Sizga effekt kerak emas) |
Uchinchi qatordagi updater keyingi darsdagi taymerda kerak bo'ladi: setInterval ichida setSeconds((s) => s + 1) — seconds massivga kirmaydi, taymer har soniyada qayta yaratilmaydi.
Diqqat:
// eslint-disable-next-line react-hooks/exhaustive-deps— React kodida eng xavfli izohlardan biri. Uni ko'rsangiz, kod ko'rigida birinchi savol: "qaysi qiymat massivdan chiqarilgan va effekt uning eskirgan nusxasi bilan ishlasa nima bo'ladi?"
6. Vazifalar qadami: kanondagi massivlar
refactor/effektlar branch'ida ishni davom ettiramiz. Eslatma: kanonda #26–#28 qadamlari bitta commit — biz uni uch darsga bo'lib o'qiyapmiz, commit esa useEffect III darsi oxirida. Bugun yangi fayl yo'q — kanondagi oltita effektning massivini bittalab o'qiymiz (to'liq kod — useEffect III darsida, cleanup bilan):
| Effekt | Massiv | Nega aynan shunday |
|---|---|---|
localStorage (saqla) |
[vazifalar] |
ro'yxat o'zgarsa — saqlash |
boshqa tablar (tingla) |
[] |
obuna bir marta; ichida faqat set funksiyalari |
server (sinxronla) |
[boshlangichRoyxat] |
props, ochilgandan keyin o'zgarmaydi — bir marta |
internet (online/offline) |
[vazifalar] |
"online" da joriy ro'yxat kerak |
URL (popstate) |
[] |
faqat set funksiyalari va URL'dan o'qish |
pagehide |
[] |
modul darajasidagi kechiktiruvchi |
Uchinchi qatorga qarang. Server effekti [] emas, [boshlangichRoyxat] — chunki effekt ichida shu props ishlatiladi. Amalda u o'zgarmaydi (main.tsx uni bir marta beradi), shuning uchun effekt bir marta ishlaydi. Lekin massiv halol: agar kimdir keyinroq boshqa ro'yxat bersa, effekt qayta sinxronlaydi. Kanondagi izoh:
// #28: server — ochilganda bir marta (boshlangichRoyxat o'zgarmaydi).Ikkinchi va beshinchi qator — [], lekin ular aldash emas. Ichida ishlatilgan narsalar: setVazifalar, setTahrirId, setFiltr (barqaror set funksiyalari) va modul darajasidagi funksiyalar (filtrniOl, paketniTekshir). Reaktiv qiymat yo'q — ESLint ham jim. Kanondagi server-sinxron.ts tur izohida shu fakt yozilgan:
/** App'ning state almashtiruvchilari (useState setter'lari — barqaror) */To'rtinchi qator — eng qiziqarlisi. Kanon izohi (aynan):
// #28: internet. "online" da joriy ro'yxat bilan solishtiramiz —
// vazifalar bog'liqlik: har o'zgarishda tinglovchi yangisiga almashadi
// (17/#31 da useEffectEvent bilan bu kerak bo'lmaydi)Massiv halol — online ishlovchisi vazifalar ni o'qiydi. Lekin narx bor: har vazifa belgilanganda online tinglovchisi olib tashlanib, qayta ulanadi. Bu xato emas, lekin isrof. Uni useEffectEvent darsida o'lchab, tuzatamiz.
vazifalar ning ESLint sozlamasida exhaustive-deps — warn, npm run lint esa --max-warnings=0 bilan. Demak bitta sariq ogohlantirish ham commit'ni to'xtatadi (husky) va CI'ni yiqitadi. Kanonda bitta ham eslint-disable izohi yo'q.
7. Ko'p uchraydigan xatolar
| Belgi | Sabab | Davosi |
|---|---|---|
| effekt hech narsa o'zgarmasa ham ishlaydi | massivda komponent ichidagi obyekt/funksiya | primitiv maydon, effekt ichiga yoki tashqariga |
The 'x' object makes the dependencies … change on every render |
o'sha | o'sha |
missing dependency: 'x' |
effekt x ni ishlatadi, massivda yo'q |
x ni qo'shing yoki effektni x siz yozing |
| ekran yangi, tashqi tizim eski | massiv aldangan ([]) |
ESLint'ni o'chirmang, massivni to'g'rilang |
[] + setCount(count + 1) — son 1 da qotadi |
eskirgan count |
updater: setCount((c) => c + 1) |
| massivni qo'shganda — cheksiz sikl | effekt o'zi o'zgartirgan qiymatga bog'liq | hosilaviy qiymat — effektsiz |
Oxirgi qator haqida. ESLint "qo'shing" deydi, siz qo'shasiz — va sikl boshlanadi. Bu ESLint xatosi emas: u effekt ishlatgan narsani ko'rsatyapti. Muammo — effektning o'zida: u o'zi o'zgartirgan narsaga bog'liq. Bunday holatda massivni emas, effektni qayta o'ylang (useEffect I darsidagi 3-mashq).
8. Mashqlar
Mashqlar kurs/mashqlar/17/27-dependency-massivi/ da. Har yechimni «Ishga tushir» bilan sinang.
1-mashq (oson): effekt qayta ishlaydimi?
Har massiv uchun javob bering: oldingi chizishdan keyin price 35000, dish "Osh" edi. Yangi chizishda ham xuddi shunday (price — son, dish — satr, order — komponent ichida { dish, price } deb yaratilgan obyekt).
[price, dish]— effekt ishlaydimi (ha/yo'q):[order]— effekt ishlaydimi (ha/yo'q):[order.price]— effekt ishlaydimi (ha/yo'q):
Yechim
[price, dish] — Object.is(35000, 35000) va Object.is("Osh", "Osh") — ikkalasi true, effekt o'tkazib yuboriladi. [order] — order har chizishda yangi obyekt, Object.is — false, effekt ishlaydi. [order.price] — massivga son tushadi, qiymati o'sha — o'tkazib yuboriladi.
2-mashq (o'rta): tab nomini tuzating
Komponent tab nomini mehmon ismi va taomlar soni bilan yangilashi kerak, lekin massiv aldangan. Blok ismni yozib, taomni ikki marta qo'shadi. Massivni tuzating: konsolda har o'zgarishdan keyin to'g'ri tab nomi chiqsin, ortiqcha ishga tushish bo'lmasin. Effekt ichidagi label obyektiga e'tibor bering — «Uchta davo» bo'limidagi ikkinchi davo.
import { useEffect, useState } from "react";
function App() {
const [guest, setGuest] = useState("");
const [count, setCount] = useState(0);
const label = { guest, count };
useEffect(() => {
document.title = `${label.guest || "Mehmon"}: ${label.count} ta`;
console.log("tab:", document.title);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
return (
<div>
<input
aria-label="Ism"
value={guest}
onChange={(e) => setGuest(e.target.value)}
/>
<button onClick={() => setCount(count + 1)}>Taom +</button>
</div>
);
}Konsolda:
tab: Mehmon: 0 taYechim
import { useEffect, useState } from "react";
function App() {
const [guest, setGuest] = useState("");
const [count, setCount] = useState(0);
useEffect(() => {
const label = { guest, count }; // obyekt — effekt ichida
document.title = `${label.guest || "Mehmon"}: ${label.count} ta`;
console.log("tab:", document.title);
}, [guest, count]);
return (
<div>
<input
aria-label="Ism"
value={guest}
onChange={(e) => setGuest(e.target.value)}
/>
<button onClick={() => setCount(count + 1)}>Taom +</button>
</div>
);
}Konsolda:
tab: Mehmon: 0 ta
tab: Malika: 0 ta
tab: Malika: 1 ta
tab: Malika: 2 talabel effekt ichiga ko'chdi — massivda uning xom ashyosi: guest va count (ikkalasi primitiv). eslint-disable izohi olib tashlandi: ESLint endi jim, chunki massiv halol. [label] deb yozsangiz ham ishlardi, lekin effekt har chizishda ishga tushardi.
3-mashq (qiyin): obyekt prop'dan keladi
MenuBadge komponenti ota'dan options obyektini oladi: { category, highlight }. Ota har chizishda yangi obyekt beradi (<MenuBadge options={{ category, highlight: true }} />). Effekt category ga qarab tab nomini yozadi. Hozir ota'dagi boshqa state (n) o'zgarganda ham effekt ishlayapti. MenuBadge ni shunday o'zgartiringki, effekt faqat category o'zgarganda ishlasin. Ota'ga tegmang. Ishora: «Uchta davo» dagi birinchi davo — obyektdan primitiv maydonni effektdan oldin ajratib oling.
import { useEffect, useState } from "react";
function MenuBadge({ options }) {
useEffect(() => {
document.title = `Bahor — ${options.category}`;
console.log("effekt:", document.title);
}, [options]);
return <p>{options.category}</p>;
}
function App() {
const [category, setCategory] = useState("taom");
const [n, setN] = useState(0);
return (
<div>
<MenuBadge options={{ category, highlight: true }} />
<button onClick={() => setN(n + 1)}>+1</button>{" "}
<button onClick={() => setCategory("ichimlik")}>
Ichimlik
</button>
</div>
);
}Konsolda:
effekt: Bahor — taom
effekt: Bahor — taom
effekt: Bahor — ichimlik
effekt: Bahor — ichimlikYechim
import { useEffect, useState } from "react";
function MenuBadge({ options }) {
const { category } = options; // primitiv — effektdan oldin
useEffect(() => {
document.title = `Bahor — ${category}`;
console.log("effekt:", document.title);
}, [category]);
return <p>{category}</p>;
}
function App() {
const [category, setCategory] = useState("taom");
const [n, setN] = useState(0);
return (
<div>
<MenuBadge options={{ category, highlight: true }} />
<button onClick={() => setN(n + 1)}>+1</button>{" "}
<button onClick={() => setCategory("ichimlik")}>
Ichimlik
</button>
</div>
);
}Konsolda:
effekt: Bahor — taom
effekt: Bahor — ichimlikTo'rtta o'rniga ikkita. Komponent ota'ning obyektini boshqara olmaydi — u har chizishda yangi kelaveradi. Lekin komponent o'zi nimaga bog'liqligini tanlay oladi: options ga emas, category satriga. Destrukturizatsiya (Obyekt destructuring) bu yerda shunchaki qulaylik emas, balki bog'liqlikni toraytirish.
4-mashq: Vazifalar qadami
refactor/effektlar branch'ida «Vazifalar qadami: kanondagi massivlar» jadvalidagi oltita massivni o'z kodingiz bilan solishtiring. npm run lint ni ishga tushiring — exhaustive-deps dan bitta ham ogohlantirish bo'lmasin.
Yechim
Tekshiruv ro'yxati:
grep -n "eslint-disable" src/App.tsx— bo'sh.- Server effekti —
[boshlangichRoyxat].[]yozsangiz, ESLintmissing dependency: 'boshlangichRoyxat'deydi. - Internet effekti —
[vazifalar]. Bu ataylab: useEffectEvent darsigacha shunday qoladi. - Set funksiyalari (
setVazifalar,setTarmoq,setTahrirId) hech bir massivda yo'q — ular barqaror.
9. Real ishda
exhaustive-deps— eng ko'p bahs qilinadigan ESLint qoidasi. Ko'p jamoalarda uerrordarajasiga ko'tariladi yoki--max-warnings=0bilan ishlatiladi (vazifalardagidek).- Obyekt bog'liqligi — chat ulanishlari, xarita vidjetlari va grafik kutubxonalarida ko'p uchraydigan sekinlik sababi: har chizishda qayta ulanish yoki qayta chizish. Profiler'da (Performance'ni o'lchash) birinchi qidiriladigan narsa.
- React Compiler (React Compiler) komponent ichidagi obyekt va funksiyalarni avtomatik saqlab turadi. U yoqilgan loyihalarda bu darsdagi muammolarning bir qismi o'z-o'zidan yo'qoladi — lekin massivni aldash muammosi qoladi.
- Intervyu savollari: "React bog'liqliklarni qanday solishtiradi?" (
Object.is, har element alohida), "nega obyekt bog'liqligi effektni har safar ishga tushiradi?", "exhaustive-depsni o'chirish nega xavfli?".
Xulosa
- Massiv: yo'q — har chizishda;
[]— bir marta;[a, b]— biri o'zgarganda. Birinchi chizishda effekt doim ishlaydi. - React har elementni
Object.isbilan solishtiradi: primitivlar — qiymati, obyekt/massiv/funksiya — havolasi bo'yicha. - Komponent ichida yaratilgan obyekt va funksiya har chizishda yangi → effekt har safar ishlaydi. Davo: primitiv maydon, effekt ichiga yoki komponentdan tashqariga.
- Massiv — effekt ishlatgan reaktiv qiymatlar ro'yxati (fakt, tanlov emas). Set funksiyalari va ref'lar barqaror.
- Massivni aldash — eskirgan closure: ekran yangi, tashqi tizim eski.
eslint-disableo'rniga kodni o'zgartiring. vazifalar: oltita effektning massivi halol;--max-warnings=0bitta ogohlantirishni ham o'tkazmaydi.
Keyingi dars: useEffect III: cleanup, race condition va AbortController — effekt boshlagan ishni (taymer, obuna, so'rov) qanday tozalash va kech kelgan javob ekranni buzmasligi.
Manbalar
- React:
useEffect— "Specifying reactive dependencies", "Removing unnecessary object/function dependencies" — react.dev/reference/react/useEffect - React: "Lifecycle of Reactive Effects", "Removing Effect Dependencies" — react.dev/learn
- MDN:
Object.is()— developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/is
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!