Mundarija (29)
- Bu darsda
- 1. Nega bu kerak?
- 2. Mif: "effekt — mount va unmount"
- 2.1 Eski fikrlash
- 2.2 Effektning nuqtai nazari
- 3. Reaktiv qiymatlar
- 3.1 Effekt nimaga "reaksiya" qiladi
- 3.2 Hisoblangan qiymat ham reaktiv
- 4. StrictMode: dev rejimdagi sinov
- 4.1 Nima qiladi
- 4.2 Cleanup bo'lmasa — xato ko'rinadi
- 4.3 Yangilanishda takror yo'q
- 4.4 Production'da — yo'q
- 5. "Bir martalik" ishlar
- 5.1 Analytics: ikki marta — normal
- 5.2 Xarid: effekt emas, hodisa
- 5.3 Ilovani bir marta sozlash
- 5.4 Ma'lumot olish: ikki so'rov
- 6. StrictMode yana nimani tekshiradi
- 7. Vazifalar kuzatuvi
- 8. Ko'p uchraydigan xatolar
- 9. Mashqlar
- 1-mashq (oson): StrictMode konsoli
- 2-mashq (o'rta): ikki ulanishni tuzating
- 3-mashq (qiyin): stolni almashtirish
- 4-mashq: Vazifalar kuzatuvi
- 10. Real ishda
- Xulosa
- Manbalar
Effekt hayot sikli va StrictMode: nega useEffect dev'da ikki marta ishlaydi
Qisqacha: Effektni komponentning "tug'ilishi va o'limi" (mount/unmount) bilan emas, sinxronlashni boshlash va to'xtatish sikli bilan o'ylang. Komponent ekranda turgan vaqt ichida effekt bir necha marta boshlanib, to'xtashi mumkin — har safar bog'liqligi o'zgarganda. StrictMode dev rejimda buni ataylab sinaydi: har effekt uchun
setup → cleanup → setupqiladi. Cleanup to'g'ri bo'lsa, foydalanuvchi farqni sezmaydi. Sezsa — cleanup'da xato bor, va u production'da ham bor. Production'da takror yo'q. StrictMode'ni o'chirish yoki "bir marta ishladimi" bayrog'i — davo emas.
Bu darsda
- Effektni "mount/unmount" emas, "boshla — to'xtat" deb o'ylay olasiz va farqini misolda ko'rsatasiz.
- StrictMode dev'da effekt bilan nima qilishini konsolda kuzatasiz.
- Ikki marta ishlaganda buziladigan effektni topib, cleanup bilan tuzatasiz.
- Reaktiv qiymat nima ekanini va qaysilari effektni qayta ishga tushirishini aytasiz.
- Analytics, xarid va ilovani sozlash kabi "bir martalik" ishlar uchun to'g'ri joyni tanlaysiz.
Oldin bilishingiz kerak: useEffect III: cleanup, useEffect II: dependency massivi, Birinchi React loyiha (StrictMode).
1. Nega bu kerak?
Birinchi React loyiha darsida StrictMode komponentni dev rejimda ikki marta chaqirishini o'lchagan edik va "effektlarni ham ikki marta ishga tushiradi" deb va'da bergan edik. Oldingi useEffect III darsida buni vazifalar ning tarmoq jurnalida ko'rdik: bitta ochilishda ikki GET, birinchisi bekor qilingan.
Sardorning birinchi reaksiyasi tushunarli edi: "Ikki marta so'rov — server yuklanadi! Ikki marta analytics — statistika buziladi!" U ikki "tuzatish" o'yladi: main.tsx dan <StrictMode> ni olib tashlash yoki effekt ichiga "allaqachon ishladimi?" bayrog'ini qo'yish. Ikkalasi ham noto'g'ri. Bugun nega ekanini va StrictMode aslida qanday sovg'a ekanini ko'ramiz.
Buning uchun avval effekt haqidagi bitta keng tarqalgan mifni buzish kerak. Hayotiy o'xshatish: ofitsiantning planshet ulanishi. Ofitsiant smenaga kelganda planshet stolga ulanadi — bu "komponent tug'ildi" emas. Ofitsiant boshqa stolga o'tsa, planshet eski stoldan uziladi va yangisiga ulanadi. Smena davomida bu o'nlab marta bo'ladi. Ulanish — komponentning hayoti emas, hozir qaysi stolga xizmat qilayotganining aksi.
2. Mif: "effekt — mount va unmount"
2.1 Eski fikrlash
React'da hooklardan oldin class komponentlar bor edi (Class komponentlarni o'qish darsida eski kodni o'qishni o'rganamiz). Ularda "hayot sikli metodlari" bor edi: componentDidMount (komponent paydo bo'ldi), componentDidUpdate (yangilandi), componentWillUnmount (yo'qolmoqda). Ko'p maqola va eski kurslarda shunday jadval uchraydi: "useEffect(fn, []) — bu componentDidMount, cleanup esa — componentWillUnmount".
Bu jadval yarim haqiqat va xavfli. U sizni "komponent hayotining qaysi nuqtasida nima qilay?" deb o'ylashga majbur qiladi. Natijada [] ga hamma narsani tiqib, massivni aldash boshlanadi (useEffect II).
Mount (mount) — komponent birinchi marta ekranga qo'yilishi; unmount (unmount) — ekrandan butunlay olib tashlanishi. Bu so'zlar hali ham foydali, lekin effekt uchun emas, komponent uchun.
2.2 Effektning nuqtai nazari
React hujjati effektni boshqacha o'ylashni so'raydi. Effekt — bitta sinxronlash jarayoni: "stol 5 ga ulangan bo'l". Uning faqat ikki harakati bor: boshlash (setup) va to'xtatish (cleanup). Effektning o'zi komponent qachon tug'ilganini bilmaydi va bilishi shart emas. U bitta savolga javob beradi: "hozirgi props va state bilan nimaga ulanishim kerak?"
import { useEffect, useState } from "react";
function connect(table) {
console.log(`ulandi: stol ${table}`);
return () => console.log(`uzildi: stol ${table}`);
}
function Waiter({ table }) {
useEffect(() => {
const disconnect = connect(table); // boshlash
return disconnect; // to'xtatish
}, [table]);
return <p>Xizmatda: stol {table}</p>;
}
function App() {
const [table, setTable] = useState(5);
const [onShift, setOnShift] = useState(true);
return (
<div>
{onShift && <Waiter table={table} />}
<button onClick={() => setTable(7)}>Stol 7</button>{" "}
<button onClick={() => setOnShift(false)}>Yopish</button>
</div>
);
}Konsolda:
ulandi: stol 5
uzildi: stol 5
ulandi: stol 7
uzildi: stol 7Ikki nuqtai nazardan bir xil voqealar:
| Voqea | Komponent nuqtai nazari | Effekt nuqtai nazari |
|---|---|---|
| ochilish | Waiter mount bo'ldi |
stol 5 bilan sinxronlash boshlandi |
| «Stol 7» | Waiter yangilandi (props) |
stol 5 to'xtadi, stol 7 boshlandi |
| «Yopish» | Waiter unmount bo'ldi |
stol 7 to'xtadi |
Komponentning bitta hayoti — effektning ikkita sikli. Agar "faqat mount'da ulanaman" deb [] yozganingizda, «Stol 7» dan keyin planshet hamon stol 5 ga ulangan bo'lardi. Effekt nuqtai nazaridan o'ylaganingizda esa massiv o'z-o'zidan to'g'ri chiqadi: "men table bilan sinxronlayman" → [table].
stateDiagram-v2
[*] --> Ulangan5: setup (stol 5)
Ulangan5 --> Uzilgan: cleanup (stol 5)
Uzilgan --> Ulangan7: setup (stol 7)
Ulangan7 --> [*]: cleanup (stol 7)Diagrammaga qarang: unda "mount" ham, "update" ham yo'q — faqat ikki holat (ulangan, uzilgan) va ikki o'tish (setup, cleanup). Har qanday ketma-ketlik shu ikki o'tishdan yig'iladi.
Tekshirib ko'ring: Komponent ekranda turganda effekt uch marta boshlanib, ikki marta to'xtadi. Komponent hali ham ekranda. Effekt necha marta to'xtashi kerak va qachon?
Javob
Yana bir marta — komponent olib tashlanganda yoki bog'liqlik keyingi safar o'zgarganda. Har "boshlash" ning o'z "to'xtatish" i bor: uch setup — oxir-oqibat uch cleanup. Hozir ochiq bitta sinxronlash qolgan.
3. Reaktiv qiymatlar
3.1 Effekt nimaga "reaksiya" qiladi
useEffect II darsida reaktiv qiymat atamasini kiritdik: chizishdan chizishga o'zgarishi mumkin bo'lgan qiymat. Endi uni effekt nuqtai nazaridan ko'ramiz. Effekt ichida o'qilgan har reaktiv qiymat — sinxronlashning bir qismi. U o'zgarsa, eski sinxronlash noto'g'ri bo'lib qoladi va qayta boshlash kerak.
| Qiymat | Reaktivmi | Nega |
|---|---|---|
props (table) |
ota boshqa qiymat berishi mumkin | |
state (category) |
set… bilan o'zgaradi |
|
komponent ichida ulardan hisoblangan (const url = …table…) |
manbasi reaktiv | |
komponentdan tashqaridagi const SERVER = "…" |
hech qachon o'zgarmaydi | |
set… funksiyalari |
React barqaror beradi | |
useRef obyekti (useRef I) |
barqaror quti |
3.2 Hisoblangan qiymat ham reaktiv
Ko'p qoqiladigan joy — uchinchi qator. Sardor manzilni effektdan oldin yasadi:
import { useEffect, useState } from "react";
const SERVER = "https://ilmhamroh.uz/api/mashq"; // reaktiv emas
function App() {
const [category, setCategory] = useState("taom");
const url = `${SERVER}/menyu?turkum=${category}`; // reaktiv!
useEffect(() => {
console.log("sinxron:", url);
}, [url]);
return (
<button onClick={() => setCategory("ichimlik")}>Ichimlik</button>
);
}Konsolda:
sinxron: https://ilmhamroh.uz/api/mashq/menyu?turkum=taom
sinxron: https://ilmhamroh.uz/api/mashq/menyu?turkum=ichimlikurl — satr, category dan hisoblangan. U ham reaktiv, shuning uchun massivda. SERVER esa massivda yo'q — u komponentdan tashqarida va ESLint uni so'ramaydi. Agar SERVER ni komponent ichiga ko'chirsangiz, ESLint uni massivga qo'shishni so'raydi. U har safar bir xil satr bo'lgani uchun effekt baribir ortiqcha ishlamaydi. Lekin ma'nosi o'zgaradi: endi u "komponentga tegishli" qiymat.
4. StrictMode: dev rejimdagi sinov
4.1 Nima qiladi
StrictMode dev rejimda har komponentni ekranga qo'ygandan keyin bir marta ataylab "olib tashlab, qaytadan qo'yadi". Faqat effektlar va ref'lar uchun: state saqlanadi, DOM qayta yaratilmaydi. Natijada har effekt: setup → cleanup → setup. Bu — «Effektning nuqtai nazari» bo'limidagi g'oyaning avtomatik sinovi: "effektingiz har qanday boshla-to'xtat ketma-ketligiga bardosh beradimi?"
Ofitsiant misolini StrictMode bilan ishga tushiramiz. Bu safar ochiq ulanishlar sonini ham sanaymiz:
import { StrictMode, useEffect } from "react";
import { createRoot } from "react-dom/client";
let open = 0; // ochiq ulanishlar (server tomonida)
function connect(table) {
open++;
console.log(`ulandi: stol ${table} (ochiq: ${open})`);
return () => {
open--;
console.log(`uzildi: stol ${table} (ochiq: ${open})`);
};
}
function Waiter({ table }) {
console.log("render");
useEffect(() => connect(table), [table]);
return <p>Xizmatda: stol {table}</p>;
}
createRoot(document.getElementById("root")).render(
<StrictMode>
<Waiter table={5} />
</StrictMode>,
);Konsolda:
render
render
ulandi: stol 5 (ochiq: 1)
uzildi: stol 5 (ochiq: 0)
ulandi: stol 5 (ochiq: 1)Ikki narsa ikki marta: render (komponent funksiyasi — Birinchi React loyiha darsidagi o'lchov) va effekt (setup → cleanup → setup). Oxirgi qatorga qarang: ochiq: 1. Foydalanuvchi uchun natija bitta ulanish bilan bir xil. useEffect(() => connect(table), [table]) — connect qaytargan funksiya to'g'ridan-to'g'ri cleanup bo'ldi.
| Render | Commit | Effekt | Cleanup |
|---|---|---|---|
1-qadam: Waiter × 2 (dev) |
<p> DOM'ga |
setup → ochiq 1 | — |
| 2-qadam (sinov): — | — | — | cleanup → ochiq 0 |
| 3-qadam (sinov): — | — | setup → ochiq 1 | — |
4.2 Cleanup bo'lmasa — xato ko'rinadi
Endi cleanup'ni "unutamiz":
import { StrictMode, useEffect } from "react";
import { createRoot } from "react-dom/client";
let open = 0;
function connect(table) {
open++;
console.log(`ulandi: stol ${table} (ochiq: ${open})`);
return () => {
open--;
};
}
function Waiter({ table }) {
useEffect(() => {
connect(table); // ❌ uzish funksiyasi tashlab yuborildi
}, [table]);
return <p>Xizmatda: stol {table}</p>;
}
createRoot(document.getElementById("root")).render(
<StrictMode>
<Waiter table={5} />
</StrictMode>,
);Konsolda:
ulandi: stol 5 (ochiq: 1)
ulandi: stol 5 (ochiq: 2)Bitta ofitsiant — ikkita ochiq ulanish. Bu StrictMode'ning "xatosi" emas: u production'dagi kelajakdagi xatoni oldindan ko'rsatdi. StrictMode'siz bu kod birinchi ochilishda to'g'ri ko'rinardi. Lekin table har o'zgarganda yangi ulanish qo'shilib, eskisi ochiq qolardi — o'sha oqish. StrictMode uni birinchi sekundda, sizning kompyuteringizda, dev rejimda ko'rsatdi.
Maslahat: Qoida juda sodda: dev'da effekt ikki marta ishlaganda foydalanuvchi farqni sezsa — cleanup'ni tuzating. Sezmasa — hammasi joyida, ikkinchi ishga tushishga e'tibor bermang.
4.3 Yangilanishda takror yo'q
StrictMode sinovi faqat birinchi marta ekranga qo'yilganda bo'ladi. Keyingi chizishlarda effekt odatdagidek ishlaydi:
import { StrictMode, useEffect, useState } from "react";
import { createRoot } from "react-dom/client";
function App() {
const [n, setN] = useState(0);
useEffect(() => {
console.log("setup", n);
return () => console.log("cleanup", n);
}, [n]);
return <button onClick={() => setN(n + 1)}>+</button>;
}
createRoot(document.getElementById("root")).render(
<StrictMode>
<App />
</StrictMode>,
);Konsolda:
setup 0
cleanup 0
setup 0
cleanup 0
setup 1Dastlabki uch qator — StrictMode sinovi. Keyingi ikkitasi — oddiy "bog'liqlik o'zgardi": eski cleanup, yangi setup.
4.4 Production'da — yo'q
StrictMode faqat dev'da ishlaydi: npm run build dan keyin u hech narsa qilmaydi. Buni Birinchi React loyiha darsida o'lchagan edik (dev — 4 qator, preview — 2 qator). vazifalar da ham xuddi shunday: npm run dev da ikki GET (birinchisi bekor qilinadi), build qilingan dist/ da — bitta.
Saytdagi «Ishga tushir» oynasida ham React'ning dev versiyasi ishlaydi. Shuning uchun <StrictMode> bilan yozilgan bloklarda takrorni o'z ko'zingiz bilan ko'rasiz.
5. "Bir martalik" ishlar
5.1 Analytics: ikki marta — normal
«Bahor» Jasur akaga "menyu necha marta ochildi" statistikasini ko'rsatadi. Har ochilishda serverga menyu_ochildi hodisasi yuboriladi:
import { StrictMode, useEffect } from "react";
import { createRoot } from "react-dom/client";
function sendEvent(name) {
console.log("analytics:", name); // haqiqiy ilovada — serverga
}
function Menu() {
useEffect(() => {
sendEvent("menyu_ochildi");
}, []);
return <h1>Menyu</h1>;
}
createRoot(document.getElementById("root")).render(
<StrictMode>
<Menu />
</StrictMode>,
);Konsolda:
analytics: menyu_ochildi
analytics: menyu_ochildiDev'da ikki marta. Bu muammomi? React hujjati aniq javob beradi: yo'q. Production'da bir marta yuboriladi. Dev statistikasi esa baribir haqiqiy foydalanuvchilarniki bilan aralashmasligi kerak — dev'da hodisalarni umuman yubormaslik yoki alohida "dev" loyihaga yuborish odatiy amaliyot. Bu yerda cleanup kerak emas: "yuborildi" ni qaytarib bo'lmaydi va bunga hojat ham yo'q.
5.2 Xarid: effekt emas, hodisa
Boshqa holat: "Buyurtma berish" — serverga POST. Sardor uni effektga qo'ydi: "buyurtma sahifasi ochilsa — yubor". Dev'da ikki buyurtma! Lekin bu yerda StrictMode haqiqiy xatoni ko'rsatdi: buyurtma sahifa ochilgani uchun emas, mehmon tugmani bosgani uchun yuborilishi kerak. Sahifa qayta ochilsa (Orqaga, yangilash), effekt yana buyurtma yuborardi — production'da ham.
Qoida: foydalanuvchi harakatiga javob — hodisa ishlovchisida (Hodisalarni boshqarish). Effekt — faqat "ekranda shu turibdi, tashqi tizim mos bo'lsin". Bu farq Sizga effekt kerak emas darsining asosi.
Tekshirib ko'ring: Uch ish bor: (a) menyu ochilganda analytics'ga "ko'rildi" yuborish; (b) «Buyurtma berish» bosilganda serverga POST; (c) sahifa ochilganda chat serveriga ulanish. Qaysi biri effektda, qaysi biri hodisa ishlovchisida bo'lishi kerak? Qaysi biriga cleanup kerak?
Javob
(a) — effekt, cleanup shart emas: dev'dagi takror zararsiz, production'da bir marta. (b) — hodisa ishlovchisi: sabab — mehmonning bosishi, sahifaning ochilishi emas. (c) — effekt va cleanup (uzish) albatta: busiz StrictMode ikkita ulanishni ko'rsatadi, production'da esa sahifa almashganda ulanishlar to'planadi.
5.3 Ilovani bir marta sozlash
Ba'zi ishlar butun ilova uchun bir marta bo'ladi: kutubxonani ishga tushirish, tokenni tekshirish. Ular komponentga emas, modulga tegishli. Ikki yo'l:
import { StrictMode, useEffect } from "react";
import { createRoot } from "react-dom/client";
let didInit = false; // modul darajasida — komponentdan tashqarida
function App() {
useEffect(() => {
if (didInit) return;
didInit = true;
console.log("ilova sozlandi"); // bir marta, dev'da ham
}, []);
return <p>Bahor</p>;
}
createRoot(document.getElementById("root")).render(
<StrictMode>
<App />
</StrictMode>,
);Konsolda:
ilova sozlandiYoki undan ham soddaroq — kodni umuman komponentdan tashqariga, main.tsx ga (createRoot dan oldin) yozish. Bu yo'lni vazifalar tanlagan: tema paneli, Service Worker ro'yxatdan o'tishi va Web Vitals — main.tsx da, App dan tashqarida (useEffect I dagi kanon main.tsx ni eslang).
Diqqat: Komponent ichida "allaqachon ishladimi?" bayrog'ini qo'yish (ko'pincha keyingi darsdagi
useRefbilan) — StrictMode'ni "aldash". U takrorni yashiradi, lekin cleanup'dagi xatoni tuzatmaydi. Bundan tashqari,tableo'zgarganda ham effekt endi qayta ulanmaydi. Modul darajasidagididInitdan farqli — u butun ilova uchun bitta bo'lgani uchun to'g'ri.
5.4 Ma'lumot olish: ikki so'rov
Effektda fetch dev'da ikki marta yuboriladi. useEffect III dagi AbortController cleanup'i bilan birinchisi bekor qilinadi — natija bitta. vazifalar ning haqiqiy dev jurnali:
BEKOR GET /api/mashq/vazifalar/de96… — net::ERR_ABORTED ← 1-effekt, cleanup bekor qildi
200 GET /api/mashq/vazifalar/de96…
200 PUT /api/mashq/vazifalar/de96… ← server kalitni bilmadi — ro'yxat yuborildiAgar cleanup bo'lmaganda, ikkala GET ham javob qaytarardi va ikkalasi ham "server kalitni bilmaydi" deb ikki PUT yuborardi. StrictMode buni darhol ko'rsatgan bo'lardi. Ikki so'rov server uchun qimmat bo'lsa — bu effektda ma'lumot olishning o'z kamchiligi. Bu haqda Effektda ma'lumot olish darsida gaplashamiz.
6. StrictMode yana nimani tekshiradi
To'liq ro'yxat — StrictMode chuqur darsida. Qisqacha:
| Tekshiruv | Qaysi xatoni ochadi |
|---|---|
| komponent funksiyasi ikki marta | chizish paytidagi yon ta'sir (toza emas) |
| effekt: setup → cleanup → setup | cleanup yo'q yoki noto'liq |
| ref callback: ikki marta (React 19) | ref cleanup yo'q (useRef II) |
| eskirgan API'lar | ogohlantirish |
Uchinchi qator haqida bir og'iz: DOM elementiga funksiya bilan ulanish ham setup → cleanup → setup sinovidan o'tadi. Bu React 19 da qo'shildi va useRef II darsida ko'ramiz.
7. Vazifalar kuzatuvi
Bu dars vazifalar kodini o'zgartirmaydi — useEffect III dagi commit allaqachon StrictMode sinovidan o'tadi. O'rniga kanondagi oltita effektni shu darsning savoli bilan tekshiramiz: "setup → cleanup → setup — foydalanuvchi farq sezadimi?"
| Effekt | Ikki marta ishlasa | Sezadimi |
|---|---|---|
localStorage (saqla) |
bir xil ro'yxat ikki marta yoziladi | yo'q |
boshqa tablar (tingla) |
obuna → bekor → obuna | yo'q (bitta tinglovchi) |
server (sinxronla) |
GET → bekor → GET | yo'q (bitta javob) |
internet, URL, pagehide |
tinglovchi → olib tashlash → tinglovchi | yo'q |
Hammasi "yo'q" — demak kanondagi effektlar to'g'ri yozilgan. main.tsx dagi <StrictMode> saqlanadi.
8. Ko'p uchraydigan xatolar
| Belgi | Sabab | Davosi |
|---|---|---|
| dev'da hamma narsa ikki marta | StrictMode | bu xato emas — foydalanuvchi farq sezadimi, tekshiring |
| dev'da ikkita ulanish, ikkita tinglovchi | cleanup yo'q | cleanup qaytaring |
| dev'da ikki buyurtma (POST) | harakat effektda | hodisa ishlovchisiga ko'chiring |
<StrictMode> o'chirildi, "tuzaldi" |
xato yashirildi, qolgan | qaytaring, cleanup'ni tuzating |
| "bir marta ishladimi" bayrog'i komponentda | StrictMode aldandi | modul darajasi yoki to'g'ri cleanup |
[] — "mount'da bir marta" deb |
massiv aldangan | effekt nuqtai nazaridan o'ylang |
9. Mashqlar
Mashqlar kurs/mashqlar/17/29-effekt-hayot-sikli/ da. Har yechimni «Ishga tushir» bilan sinang.
1-mashq (oson): StrictMode konsoli
Kodni ishga tushirmasdan, konsolni oldindan yozing (StrictMode yoqilgan).
import { StrictMode, useEffect } from "react";
import { createRoot } from "react-dom/client";
function Kitchen() {
useEffect(() => {
console.log("pech yoqildi");
return () => console.log("pech o'chdi");
}, []);
return <p>Oshxona</p>;
}
createRoot(document.getElementById("root")).render(
<StrictMode>
<Kitchen />
</StrictMode>,
);- Konsolda nechta qator:
- Oxirgi qator:
Yechim
Konsolda:
pech yoqildi
pech o'chdi
pech yoqildiStrictMode sinovi: setup → cleanup → setup. Oxirida pech yoqilgan — foydalanuvchi uchun bitta "yoqish" bilan bir xil.
2-mashq (o'rta): ikki ulanishni tuzating
Mehmonlar soni hisoblagichi subscribe orqali "server" ga obuna bo'ladi. StrictMode'da obunalar soni 2 bo'lib qolyapti. Effektni tuzating: oxirida obunalar: 1 bo'lsin. Ishora: subscribe obunani bekor qiluvchi funksiya qaytaradi — «StrictMode: dev rejimdagi sinov» bo'limidagi connect kabi.
import { StrictMode, useEffect } from "react";
import { createRoot } from "react-dom/client";
let subscribers = 0;
function subscribe(onGuests) {
subscribers++;
console.log("obunalar:", subscribers);
onGuests(12);
return () => {
subscribers--;
console.log("obunalar:", subscribers);
};
}
function GuestCounter() {
useEffect(() => {
subscribe((n) => console.log("mehmonlar:", n));
}, []);
return <p>Mehmonlar hisoblagichi</p>;
}
createRoot(document.getElementById("root")).render(
<StrictMode>
<GuestCounter />
</StrictMode>,
);Konsolda:
obunalar: 1
mehmonlar: 12
obunalar: 2
mehmonlar: 12Yechim
import { StrictMode, useEffect } from "react";
import { createRoot } from "react-dom/client";
let subscribers = 0;
function subscribe(onGuests) {
subscribers++;
console.log("obunalar:", subscribers);
onGuests(12);
return () => {
subscribers--;
console.log("obunalar:", subscribers);
};
}
function GuestCounter() {
useEffect(() => {
const showGuests = (n) => console.log("mehmonlar:", n);
const unsubscribe = subscribe(showGuests);
return unsubscribe;
}, []);
return <p>Mehmonlar hisoblagichi</p>;
}
createRoot(document.getElementById("root")).render(
<StrictMode>
<GuestCounter />
</StrictMode>,
);Konsolda:
obunalar: 1
mehmonlar: 12
obunalar: 0
obunalar: 1
mehmonlar: 12Oxirgi holat — bitta obuna. subscribe qaytargan funksiyani tashlab yubormaslik — butun tuzatish. Qisqa shakl ham bor: useEffect(() => subscribe(…), []) — arrow funksiya subscribe natijasini o'zi qaytaradi.
3-mashq (qiyin): stolni almashtirish
Waiter komponenti hozir faqat birinchi stolga ulanadi: massiv []. «Stol 7» bosilganda ham planshet stol 5 da qoladi. Shunday tuzatingki:
tableo'zgarganda eski stoldan uzilib, yangisiga ulansin;- StrictMode yoqilgan holda ham oxirida faqat bitta ulanish ochiq qolsin;
- konsolda har qadam ko'rinsin (
connecto'zi yozadi).
Ishora: effekt nuqtai nazaridan o'ylang — "men qaysi qiymat bilan sinxronlayapman?" va «Reaktiv qiymatlar» jadvali.
import { StrictMode, useEffect, useState } from "react";
import { createRoot } from "react-dom/client";
let open = 0;
function connect(table) {
open++;
console.log(`ulandi: ${table} (ochiq: ${open})`);
return () => {
open--;
console.log(`uzildi: ${table} (ochiq: ${open})`);
};
}
function Waiter({ table }) {
useEffect(() => {
connect(table);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
return <p>Stol {table}</p>;
}
function App() {
const [table, setTable] = useState(5);
return (
<div>
<Waiter table={table} />
<button onClick={() => setTable(7)}>Stol 7</button>
</div>
);
}
createRoot(document.getElementById("root")).render(
<StrictMode>
<App />
</StrictMode>,
);Konsolda:
ulandi: 5 (ochiq: 1)
ulandi: 5 (ochiq: 2)Yechim
import { StrictMode, useEffect, useState } from "react";
import { createRoot } from "react-dom/client";
let open = 0;
function connect(table) {
open++;
console.log(`ulandi: ${table} (ochiq: ${open})`);
return () => {
open--;
console.log(`uzildi: ${table} (ochiq: ${open})`);
};
}
function Waiter({ table }) {
useEffect(() => connect(table), [table]);
return <p>Stol {table}</p>;
}
function App() {
const [table, setTable] = useState(5);
return (
<div>
<Waiter table={table} />
<button onClick={() => setTable(7)}>Stol 7</button>
</div>
);
}
createRoot(document.getElementById("root")).render(
<StrictMode>
<App />
</StrictMode>,
);Konsolda:
ulandi: 5 (ochiq: 1)
uzildi: 5 (ochiq: 0)
ulandi: 5 (ochiq: 1)
uzildi: 5 (ochiq: 0)
ulandi: 7 (ochiq: 1)Ikki xato bitta tuzatish bilan ketdi: cleanup qaytarildi (ochiq ulanishlar 1 dan oshmaydi) va massiv halol bo'ldi ([table] — stol almashganda qayta ulanish). Konsolning dastlabki uch qatori — StrictMode sinovi, keyingi ikkitasi — «Stol 7». eslint-disable izohi olib tashlandi: endi u kerak emas.
4-mashq: Vazifalar kuzatuvi
vazifalar ni npm run dev bilan oching, DevTools → Network → Fetch/XHR. Bitta ochilishda nechta /vazifalar/ so'rovi bor va qaysi biri (canceled)? Keyin npm run build && npm run preview bilan xuddi shuni qiling.
Yechim
Dev'da: ikki GET, birinchisi (canceled) — StrictMode'ning setup → cleanup → setup sinovi va AbortController cleanup'i. Agar serverda kalit hali bo'lmasa, keyin bitta PUT. Preview'da: bitta GET (StrictMode production build'da ishlamaydi). Ikkala holatda ham ekrandagi ro'yxat bir xil — foydalanuvchi farq sezmaydi, demak effekt to'g'ri.
10. Real ishda
- StrictMode — Vite shabloni, Next.js (App Router'da sukut bo'yicha yoqilgan) va ko'p loyihalarda dev'da yoqiq. "Konsolda ikki marta" — yangi kelgan dasturchining birinchi savollaridan biri.
- Analytics kutubxonalari (Google Analytics, Yandex Metrika, PostHog — Analitika darsida) dev'da odatda o'chiriladi yoki test rejimiga o'tkaziladi — ikki marta yuborish shu bilan ham hal bo'ladi.
- Kod ko'rigida "StrictMode'ni o'chirdim, ikki marta so'rov ketayotgan edi" — qizil bayroq: cleanup yoki effektning o'zi noto'g'ri.
- Intervyu savollari: "Nega
useEffectdev'da ikki marta ishlaydi?", "useEffect(fn, [])vacomponentDidMountbir xilmi?", "StrictMode production'ga ta'sir qiladimi?".
Xulosa
- Effekt — komponent hayoti emas, bitta sinxronlash: boshlash (setup) va to'xtatish (cleanup). Komponent ekranda turganda u ko'p marta qayta boshlanishi mumkin.
- Effekt ichida o'qilgan har reaktiv qiymat (props, state, ulardan hisoblangan) — massivda; tashqi
const, set funksiyalari va ref — reaktiv emas. - StrictMode dev'da har effektni bir marta
setup → cleanup → setupqiladi. Foydalanuvchi farq sezsa — cleanup'ni tuzating; production'da takror yo'q. - Analytics'ning dev'dagi takrori — normal; xarid kabi harakat — effektda emas, hodisa ishlovchisida; ilova sozlamasi — modul darajasida.
- StrictMode'ni o'chirish va "bir marta ishladimi" bayrog'i — xatoni yashiradi, tuzatmaydi.
Keyingi dars: Sizga effekt kerak emas — eng keng tarqalgan React xatosi: hisoblanadigan qiymat va harakat uchun effekt. vazifalar da o'lchov: effekt 2 soniyada 824 xabar yubordi.
Manbalar
- React: "Lifecycle of Reactive Effects" — react.dev/learn/lifecycle-of-reactive-effects
- React: "Synchronizing with Effects" — "How to handle the Effect firing twice in development?" — react.dev/learn/synchronizing-with-effects
- React:
<StrictMode>— react.dev/reference/react/StrictMode
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!