Mundarija (27)
- Bu darsda
- 1. Nega bu kerak?
- 2. Muammo jonli
- 2.1 [table, theme] — ortiqcha qayta ulanish
- 2.2 Effekt ichida ikki xil mantiq
- 3. useEffectEvent
- 3.1 Sintaksis
- 3.2 Nega "eng so'nggi" qiymat
- 3.3 Versiya: barqaror, 19.2 dan
- 4. Qoidalar
- 4.1 Faqat effekt ichidan
- 4.2 Massivga yozilmaydi, boshqa joyga berilmaydi
- 4.3 Linterni jim qilish uchun emas
- 5. Oldin qanday edi: "latest ref"
- 6. Vazifalar qadami: online bir marta ulanadi
- 6.1 Muammo — testda
- 6.2 Tuzatish
- 6.3 Tekshiruvlar
- 7. Ko'p uchraydigan xatolar
- 8. Mashqlar
- 1-mashq (oson): reaktivmi?
- 2-mashq (o'rta): bosishlar statistikasi
- 3-mashq (qiyin): ovozsiz rejim
- 4-mashq: Vazifalar qadami
- 9. Real ishda
- Xulosa
- Manbalar
useEffectEvent: effekt ichida eng so'nggi qiymat — qayta ulanmasdan
Qisqacha:
useEffectEventeffekt ichidagi kodning bir qismini effekt hodisasiga ajratadi: u chaqirilgan paytdagi eng so'nggi props va state'ni ko'radi, lekin reaktiv emas — bog'liqliklar massiviga kirmaydi va o'zgarganda effektni qayta ishga tushirmaydi. Klassik holat: effekt stolga ulanadi ([table]), "ulandi" xabari esa joriy mavzuni (theme) ishlatadi. Mavzu o'zgarganda qayta ulanish kerak emas. React 19.2 (2025-yil oktabr) dan barqaror,vazifalardagi 19.3.0 da bor. Qoidalar: faqat effekt ichidan chaqiriladi (chizish paytida emas, boshqa komponentga berilmaydi) va linterni jim qilish uchun ishlatilmaydi.
Bu darsda
- Effekt ichida "reaktiv" va "reaktiv bo'lmagan" mantiqni ajrata olasiz.
useEffectEventbilan keraksiz qayta ulanishni olib tashlaysiz va konsolda tekshirasiz.- Uning uchta qoidasini va buzilganda chiqadigan haqiqiy xatolarni bilasiz.
- Qachon
useEffectEventkerak emasligini aytasiz. vazifalardaonlinetinglovchisining 4 marta qayta ulanishini testda ko'rib, bir martaga tushirasiz.
Oldin bilishingiz kerak: Effekt hayot sikli, useEffect II: dependency massivi, Closure tuzoqlari, Sizga effekt kerak emas.
1. Nega bu kerak?
Effekt hayot sikli darsida ofitsiant planshetini stolga uladik: useEffect(() => connect(table), [table]). Stol almashsa — qayta ulanadi, to'g'ri. Endi Jasur aka yangi talab qo'ydi: "Ulanganda planshetda «ulandi» degan xabar chiqsin — tanlangan mavzu ranglarida (yorug' yoki qorong'i)."
Xabar theme ni ishlatadi. theme — props, ya'ni reaktiv qiymat. Massiv qoidasi bo'yicha u massivga kirishi shart: [table, theme]. Natija — ofitsiant mavzuni almashtirsa, planshet stoldan uzilib, qayta ulanadi. Sababi faqat xabar rangining o'zgarishi.
Agar theme ni massivdan olib tashlasak — massivni aldash: xabar eski mavzuda chiqadi. ESLint ogohlantiradi. Ikki yomon tanlov: ortiqcha qayta ulanish yoki eskirgan qiymat.
Hayotiy o'xshatish: siz do'stingiz bilan telefonda gaplashyapsiz. U sizdan "hozir soat necha?" deb so'raydi. Soatga qarash uchun qo'ng'iroqni uzib, qayta qo'ng'iroq qilmaysiz — shunchaki soatga qaraysiz. Qo'ng'iroq (ulanish) — do'stingizga bog'liq. Soat esa — har qaraganda eng yangi qiymat, lekin u qo'ng'iroqni qayta boshlamaydi. useEffectEvent — "soatga qarash".
2. Muammo jonli
2.1 [table, theme] — ortiqcha qayta ulanish
import { useEffect, useState } from "react";
function connect(table, onConnected) {
console.log(`ulanish: stol ${table}`);
onConnected();
return () => console.log(`uzish: stol ${table}`);
}
function Waiter({ table, theme }) {
useEffect(() => {
const showNotice = () => {
console.log(`xabar: ulandi (mavzu: ${theme})`);
};
return connect(table, showNotice);
}, [table, theme]);
return <p>Stol {table}, mavzu: {theme}</p>;
}
function App() {
const [table, setTable] = useState(5);
const [theme, setTheme] = useState("yorug'");
return (
<div>
<Waiter table={table} theme={theme} />
<button onClick={() => setTheme("qorong'i")}>
Qorong'i
</button>{" "}
<button onClick={() => setTable(7)}>Stol 7</button>
</div>
);
}Konsolda:
ulanish: stol 5
xabar: ulandi (mavzu: yorug')
uzish: stol 5
ulanish: stol 5
xabar: ulandi (mavzu: qorong'i)
uzish: stol 5
ulanish: stol 7
xabar: ulandi (mavzu: qorong'i)O'rtadagi uch qator — muammo. «Qorong'i» bosildi: planshet stol 5 dan uzilib, o'sha stol 5 ga qayta ulandi. Haqiqiy ilovada bu — tarmoq so'rovi, server yuklamasi, bir soniyalik "ulanmoqda…" holati. Hammasi bitta rang uchun.
2.2 Effekt ichida ikki xil mantiq
Effektni sinchiklab o'qisak, ichida ikki xil kod bor:
| Kod | Nimaga bog'liq | Qiymat o'zgarsa |
|---|---|---|
connect(table, …) |
table |
qayta ulanish kerak |
console.log(… theme …) |
theme |
faqat keyingi xabar yangi rangda bo'lsin |
Birinchisi — reaktiv mantiq: u qiymatga "reaksiya" qilishi kerak. Ikkinchisi — reaktiv bo'lmagan mantiq: u eng so'nggi qiymatni o'qishi kerak, lekin unga reaksiya qilmasligi kerak. Muammo shundaki, effekt ikkalasini bitta qop ichiga solgan. Massiv esa butun qop uchun bitta.
Hodisa ishlovchisini eslang (Hodisalarni boshqarish): onClick ichidagi kod har doim eng so'nggi state'ni ko'radi va hech narsaga "reaksiya" qilmaydi — u faqat bosilganda ishlaydi. "Ulandi" xabari ham aslida hodisa: "ulanish sodir bo'ldi". Faqat bu hodisani foydalanuvchi emas, effekt chaqiradi.
flowchart LR
P["props: table, theme"] --> E["useEffect, massiv: table"]
P --> V["useEffectEvent: onConnected"]
E -- "table o'zgarsa" --> C["uzish va qayta ulanish"]
E -- "ulandi" --> V
V -- "chaqirilganda" --> T["eng so'nggi theme bilan xabar"]Diagrammada ikki yo'l bor. Yuqoridagisi — reaktiv: table o'zgarsa, effekt qayta ulanadi. Pastdagisi — reaktiv emas: effekt hodisasi faqat chaqirilganda theme ni o'qiydi va hech narsani qayta ishga tushirmaydi. Keyingi bo'limda shu ajratishni kodda qilamiz.
3. useEffectEvent
3.1 Sintaksis
Effekt hodisasi (Effect Event) — useEffectEvent bilan yaratilgan funksiya: effekt ichidan chaqiriladi, chaqirilgan paytdagi eng so'nggi props va state'ni ko'radi, o'zi esa reaktiv emas.
import { useEffect, useEffectEvent, useState } from "react";
function connect(table, onConnected) {
console.log(`ulanish: stol ${table}`);
onConnected();
return () => console.log(`uzish: stol ${table}`);
}
function Waiter({ table, theme }) {
// Effekt hodisasi: eng so'nggi theme, lekin reaktiv emas
const onConnected = useEffectEvent(() => {
console.log(`xabar: ulandi (mavzu: ${theme})`);
});
useEffect(() => connect(table, onConnected), [table]);
return <p>Stol {table}, mavzu: {theme}</p>;
}
function App() {
const [table, setTable] = useState(5);
const [theme, setTheme] = useState("yorug'");
return (
<div>
<Waiter table={table} theme={theme} />
<button onClick={() => setTheme("qorong'i")}>
Qorong'i
</button>{" "}
<button onClick={() => setTable(7)}>Stol 7</button>
</div>
);
}Konsolda:
ulanish: stol 5
xabar: ulandi (mavzu: yorug')
uzish: stol 5
ulanish: stol 7
xabar: ulandi (mavzu: qorong'i)Sakkiz qator o'rniga besh. «Qorong'i» bosilganda — hech narsa: qayta ulanish yo'q. «Stol 7» da — haqiqiy qayta ulanish va xabar yangi mavzu bilan. onConnected theme ning eng so'nggi qiymatini ko'rdi, garchi effekt theme haqida hech narsa bilmasa ham.
Uch narsaga e'tibor bering:
useEffectEvent(fn)— hook, komponentning yuqori darajasida (hooklar qoidalari).- Massiv —
[table].onConnectedunga kirmaydi va ESLint buni so'ramaydi. onConnectedeffekt ichidan chaqirildi (connectorqali).
| Render | Commit | Cleanup | Effekt |
|---|---|---|---|
| ochilish: stol 5, yorug' | <p> |
— | ulanish 5, xabar (yorug') |
| «Qorong'i»: stol 5, qorong'i | matn yangilandi | — | — (table o'sha) |
| «Stol 7»: stol 7, qorong'i | matn yangilandi | uzish 5 | ulanish 7, xabar (qorong'i) |
3.2 Nega "eng so'nggi" qiymat
Closure tuzoqlari darsida eskirgan closure'ni ko'rgan edik: funksiya yaratilgan paytdagi qiymatlarni "ushlab qoladi". Effekt [table] bilan faqat stol o'zgarganda qayta yaratiladi. Agar theme ni to'g'ridan-to'g'ri effekt ichida o'qisak, u effekt yaratilgan paytdagi theme bo'lardi.
useEffectEvent boshqacha ishlaydi. Har chizishda siz unga yangi funksiya berasiz (yangi theme bilan), React esa uni ichki "qutisiga" qo'yadi — commit paytida. Sizga qaytgan funksiya chaqirilganda, u o'z kodini emas, qutidagi eng oxirgi funksiyani ishga tushiradi. Shuning uchun effekt onConnected ning eski nusxasini ushlab qolsa ham, natija doim eng yangi qiymat bilan.
Yana bir detal: qaytgan funksiyaning o'zi har chizishda yangi (tekshirdik: prev === ev — false). Bu ataylab qilingan. Uni massivga yozsangiz, effekt har chizishda qayta ishlardi — shuning uchun qoida: effekt hodisasi massivga kirmaydi.
3.3 Versiya: barqaror, 19.2 dan
useEffectEvent uzoq vaqt eksperimental edi: experimental_useEffectEvent nomi bilan faqat canary versiyalarda bor edi. React 19.2 da (react.dev blogi, "React 19.2", 2025-10-01) u barqaror API sifatida chiqdi. O'sha relizda eslint-plugin-react-hooks ham uni taniydigan bo'ldi. Sayt oynasidagi React'da tekshiramiz:
import { useEffectEvent, version } from "react";
console.log("React", version, typeof useEffectEvent);Konsolda:
React 19.3.0 functionvazifalar ham 19.3.0 da. Eski loyihalarda (React 18, 19.0, 19.1) u yo'q — u yerda pastdagi «latest ref» usuli uchraydi.
Tekshirib ko'ring:
useEffectEventichidatableni ham o'qisak bo'ladimi? Masalan, xabar "stol 5 ga ulandi (yorug')" bo'lsin.
Javob
Bo'ladi: effekt hodisasi har qanday props va state'ni o'qiy oladi. Lekin table effektning o'zida reaktiv bo'lib qolishi kerak — massivda [table] turibdi, chunki ulanish unga bog'liq. Toza variant — table ni argument qilib berish: onConnected(table). Shunda hodisa aynan qaysi stol uchun chaqirilgani aniq ko'rinadi.
4. Qoidalar
4.1 Faqat effekt ichidan
Effekt hodisasini chizish paytida chaqirib bo'lmaydi. React buni ish vaqtida tekshiradi:
import { useEffectEvent, useState } from "react";
function App() {
const [theme] = useState("yorug'");
const onConnected = useEffectEvent(() => theme);
return <p>Mavzu: {onConnected()}</p>; // ❌ chizish paytida
}Konsolda:
Uncaught Error: A function wrapped in useEffectEvent can't be called during rendering."useEffectEvent ga o'ralgan funksiyani chizish paytida chaqirib bo'lmaydi." Chizish paytida kerakli qiymat — theme ning o'zi, unga o'ram kerak emas.
4.2 Massivga yozilmaydi, boshqa joyga berilmaydi
ESLint ikki xatoni ham ko'radi. Faylda effekt hodisasi massivga yozilgan va onClick dan chaqirilgan (plagin 7.1.1, qisqartirildi):
10:14 warning Functions returned from `useEffectEvent` must not be included in the dependency array. Remove `onConnected` from the list
11:33 error `onConnected` is a function created with React Hook "useEffectEvent", and can only be called from Effects and Effect Events in the same component- "
useEffectEventqaytargan funksiyalar bog'liqliklar massiviga kiritilmasligi kerak." U barqaror — massivda ma'nosi yo'q. - "
onConnected—useEffectEventbilan yaratilgan funksiya va faqat shu komponentdagi effektlar va effekt hodisalaridan chaqirilishi mumkin." Tugma uchun oddiy ishlovchi yozing. Boshqa komponentga props qilib berish ham taqiqlangan.
4.3 Linterni jim qilish uchun emas
Eng muhim qoida — yozilmagani. useEffectEvent ni "ESLint missing dependency deyapti — o'rab qo'yaman" deb ishlatish massivni aldashning yangi shakli. Savol bitta: bu qiymat o'zgarganda sinxronlash qayta boshlanishi kerakmi?
| Qiymat | Qayta boshlash kerakmi | Qayerda |
|---|---|---|
| stol raqami (qaysi xonaga ulanish) | effektda, massivda | |
| xabar rangi, ovoz yoqilganmi | effekt hodisasida | |
| server manzili | effektda | |
| analytics'ga qo'shiladigan joriy savat soni | effekt hodisasida |
Agar javob "ha" bo'lsa-yu, siz qiymatni effekt hodisasiga yashirsangiz — stol almashganda planshet eski stolda qoladi. useEffectEvent faqat "bu — effektdan chaqiriladigan hodisa" bo'lganda to'g'ri.
5. Oldin qanday edi: "latest ref"
useEffectEvent dan oldin bu muammo ref bilan yechilardi. Ref — o'zgarganda qayta chizish chaqirmaydigan "quti", uni ikki darsdan keyin o'rganamiz (useRef I). G'oya: har chizishda eng so'nggi theme ni qutiga qo'yish, effektda esa qutidan o'qish. Eski kodda shunday parchani uchratasiz:
const themeRef = useRef(theme);
useEffect(() => {
themeRef.current = theme; // har chizishdan keyin eng so'nggisi
});
useEffect(() => {
return connect(table, () => show(themeRef.current));
}, [table]);Bu ishlaydi, lekin uchta kamchiligi bor: qo'shimcha effekt va ref, kod niyatni yashiradi ("bu nima uchun?") va ESLint uni tekshira olmaydi. useEffectEvent — xuddi shu g'oyaning rasmiy, tekshiriladigan shakli. Yangi kodda — faqat u.
6. Vazifalar qadami: online bir marta ulanadi
6.1 Muammo — testda
useEffect II darsida kanondagi internet effektini ko'rgan edik: [vazifalar]. online hodisasida joriy ro'yxat bilan sinxronlash kerak, shuning uchun vazifalar massivda. Lekin bu degani — har vazifa belgilanganda online va offline tinglovchilari olib tashlanib, qayta ulanadi.
Yangi branch: refactor/effekt-hodisasi. Avval muammoni test bilan ushlaymiz. vi.spyOn(window, "addEventListener") — addEventListener chaqiruvlarini sanaydigan "josus" (Vitest: mock va spy — testlar qismida chuqur). Kanondagi test:
test("online tinglovchisi bir marta ulanadi (ro'yxat o'zgarsa ham)", async () => {
serverJavobi(ROYXAT);
const ulash = vi.spyOn(window, "addEventListener");
render(<App boshlangichRoyxat={ROYXAT} qoralama="" />);
await waitFor(() => expect(matni("aloqa")).toBe(""));
for (let i = 0; i < 3; i++) {
fireEvent.click(
screen.getByRole("checkbox", { name: "Non olish #bozor" }),
);
}
const onlayn = ulash.mock.calls.filter(([tur]) => tur === "online");
expect(onlayn).toHaveLength(1);
});Uch marta katak bosiladi, keyin "online" uchun addEventListener necha marta chaqirilgani sanaladi. Holat 28 kodida natija (haqiqiy):
× online tinglovchisi bir marta ulanadi (ro'yxat o'zgarsa ham) 129ms
AssertionError: expected [ …(4) ] to have a length of 1 but got 4
Tests 1 failed | 4 passed (5)To'rt marta: ochilishda bir va har bosishda bir. Test yiqildi — endi tuzatamiz.
6.2 Tuzatish
sinxronla(vazifalar, …) chaqiruvi — reaktiv bo'lmagan mantiq: "internet qaytdi" — hodisa, u eng so'nggi ro'yxatni o'qishi kerak, lekin ro'yxat o'zgarganda tinglovchini qayta ulash kerak emas. Kanondagi diff:
-import { useEffect, useState } from "react";
+import { useEffect, useEffectEvent, useState } from "react";
@@
+ const onlaynBoldi = useEffectEvent(() => {
+ void sinxronla(vazifalar, { setVazifalar, setTarmoq, setTahrirId });
+ });
+
+ // #28: internet — ochilganda bir marta ulanadi
useEffect(() => {
function oflayn() {
sinxronniTox();
setTarmoq("oflayn");
}
- function onlayn() {
- void sinxronla(vazifalar, {
- setVazifalar,
- setTarmoq,
- setTahrirId,
- });
- }
+ const onlayn = () => onlaynBoldi();
addEventListener("offline", oflayn);
addEventListener("online", onlayn);
return () => {
removeEventListener("offline", oflayn);
removeEventListener("online", onlayn);
};
- }, [vazifalar]);
+ }, []);E'tibor bering: addEventListener("online", onlaynBoldi) emas, const onlayn = () => onlaynBoldi(). Effekt hodisasini boshqa API'ga (bu yerda brauzerga) to'g'ridan-to'g'ri berish tavsiya etilmaydi — u faqat effekt kodi ichidan chaqirilsin. Kanondagi izoh (aynan):
// #31: effekt hodisasi — ENG SO'NGGI vazifalarni o'qiydi, lekin
// reaktiv emas: effektning bog'liqligi bo'lmaydi. #28 da effekt
// [vazifalar] ga bog'liq edi — har o'zgarishda online tinglovchisi
// olib tashlanib, qayta ulanardi (o'lchandi: 3 bosishda 4 marta)Massiv [] — va bu safar aldash emas: effekt ichida reaktiv qiymat qolmadi (setTarmoq barqaror, onlaynBoldi — effekt hodisasi). ESLint jim.
6.3 Tekshiruvlar
Tests 5 passed (5)- Commit:
refactor: online tinglovchisi useEffectEvent bilan bir marta ulanadi. npm test— node:test 147, Vitest 23 (+1 yangi test). Lint, format, tip —exit 0.- Brauzer tekshiruvi — 159/159 (oflayn → onlayn ssenariysi ham).
- Diff: 2 fayl, +26 −12. Bundle deyarli o'zgarmadi:
index-…js248.41 → 248.45 kB.
Avval yiqiladigan test, keyin tuzatish — bu tartibni TDD (test-driven development) deyishadi. Bu yerda u isbot vazifasini ham bajardi: "4 marta" — taxmin emas, o'lchov.
7. Ko'p uchraydigan xatolar
| Belgi | Sabab | Davosi |
|---|---|---|
| mavzu/ovoz o'zgarganda qayta ulanish | reaktiv bo'lmagan qiymat effekt massivida | o'sha kodni useEffectEvent ga |
can't be called during rendering |
effekt hodisasi JSX ichida chaqirilgan | qiymatning o'zini ishlating |
can only be called from Effects and Effect Events |
onClick dan yoki boshqa komponentdan |
oddiy ishlovchi yozing |
must not be included in the dependency array |
effekt hodisasi massivda | olib tashlang |
| stol almashdi, ulanish eski | reaktiv qiymat effekt hodisasiga yashirilgan | massivga qaytaring |
useEffectEvent is not a function |
React 19.2 dan eski | yangilang yoki "latest ref" |
8. Mashqlar
Mashqlar kurs/mashqlar/17/31-useeffectevent/ da. Har yechimni «Ishga tushir» bilan sinang.
1-mashq (oson): reaktivmi?
Oshxona ekrani buyurtmalar kanaliga ulanadi. Effekt ichida to'rt qiymat o'qiladi. Har biri uchun javob bering: effekt massivida qolsinmi (massiv) yoki effekt hodisasiga o'tsinmi (hodisa)?
kitchenId— qaysi oshxona kanaliga ulanish:soundOn— yangi buyurtmada ovoz chalinsinmi:serverUrl— kanal manzili:ordersCount— xabarga qo'shiladigan joriy buyurtmalar soni:
Yechim
kitchenId va serverUrl o'zgarsa — boshqa kanalga ulanish kerak: reaktiv, massivda. soundOn va ordersCount — faqat buyurtma kelganda o'qiladi; ular o'zgarganda qayta ulanish keraksiz: effekt hodisasida.
2-mashq (o'rta): bosishlar statistikasi
Sahifadagi har bosish window darajasida sanaladi va konsolga joriy savat soni bilan yoziladi. Hozir tinglovchi har count o'zgarishida qayta ulanyapti (ulandi qatorlari). useEffectEvent bilan tuzating: tinglovchi bir marta ulansin, lekin har bosishda eng so'nggi count yozilsin.
import { useEffect, useState } from "react";
function App() {
const [count, setCount] = useState(0);
useEffect(() => {
console.log("ulandi");
function handleClick() {
console.log("bosish, savatda:", count);
}
window.addEventListener("click", handleClick);
return () => window.removeEventListener("click", handleClick);
}, [count]);
return <button onClick={() => setCount(count + 1)}>Taom +</button>;
}Konsolda:
ulandi
bosish, savatda: 0
ulandi
bosish, savatda: 1
ulandiYechim
import { useEffect, useEffectEvent, useState } from "react";
function App() {
const [count, setCount] = useState(0);
const onPageClick = useEffectEvent(() => {
console.log("bosish, savatda:", count);
});
useEffect(() => {
console.log("ulandi");
const handleClick = () => onPageClick();
window.addEventListener("click", handleClick);
return () => window.removeEventListener("click", handleClick);
}, []);
return <button onClick={() => setCount(count + 1)}>Taom +</button>;
}Konsolda:
ulandi
bosish, savatda: 0
bosish, savatda: 1Bitta ulanish, qiymatlar — eng so'nggi (bosish paytida count hali oshmagan: window tinglovchisi tugmaning onClick idan keyin, lekin qayta chizishdan oldin ishlaydi). handleClick effekt ichidagi oddiy funksiya: u effekt hodisasini effekt kodi ichidan chaqiradi.
3-mashq (qiyin): ovozsiz rejim
Oshxona ekrani kitchen kanaliga ulanadi. Server xabari kelganda (blokda «Server: yangi buyurtma» tugmasi uni taqlid qiladi) ekran ovoz chaladi — agar muted o'chiq bo'lsa. Hozir «Ovozsiz» bosilganda kanal qayta ulanadi. Tuzating:
- kanal faqat
kitcheno'zgarganda qayta ulansin; - xabar kelganda eng so'nggi
mutedhisobga olinsin; onMessageeffekt hodisasi bo'lsin.
Ishora: subscribe(kitchen, onMessage) obunani bekor qiluvchi funksiya qaytaradi — «Sintaksis» bo'limidagi connect kabi. Kanalga xabarni modul darajasidagi emit() yuboradi.
import { useEffect, useState } from "react";
let listener = null; // "server" kanali — taqlid
function subscribe(kitchen, onMessage) {
console.log("ulandi:", kitchen);
listener = onMessage;
return () => {
console.log("uzildi:", kitchen);
listener = null;
};
}
const emit = (text) => listener?.(text);
function KitchenScreen({ kitchen, muted }) {
useEffect(() => {
return subscribe(kitchen, (text) => {
console.log(muted ? `🔇 ${text}` : `🔔 ${text}`);
});
}, [kitchen, muted]);
return <p>Oshxona: {kitchen}</p>;
}
function App() {
const [muted, setMuted] = useState(false);
return (
<div>
<KitchenScreen kitchen="asosiy" muted={muted} />
<button onClick={() => setMuted(true)}>Ovozsiz</button>{" "}
<button onClick={() => emit("osh × 2")}>
Server: yangi buyurtma
</button>
</div>
);
}Konsolda:
ulandi: asosiy
uzildi: asosiy
ulandi: asosiy
🔇 osh × 2Yechim
import { useEffect, useEffectEvent, useState } from "react";
let listener = null; // "server" kanali — taqlid
function subscribe(kitchen, onMessage) {
console.log("ulandi:", kitchen);
listener = onMessage;
return () => {
console.log("uzildi:", kitchen);
listener = null;
};
}
const emit = (text) => listener?.(text);
function KitchenScreen({ kitchen, muted }) {
const onMessage = useEffectEvent((text) => {
console.log(muted ? `🔇 ${text}` : `🔔 ${text}`);
});
useEffect(() => {
return subscribe(kitchen, (text) => onMessage(text));
}, [kitchen]);
return <p>Oshxona: {kitchen}</p>;
}
function App() {
const [muted, setMuted] = useState(false);
return (
<div>
<KitchenScreen kitchen="asosiy" muted={muted} />
<button onClick={() => setMuted(true)}>Ovozsiz</button>{" "}
<button onClick={() => emit("osh × 2")}>
Server: yangi buyurtma
</button>
</div>
);
}Konsolda:
ulandi: asosiy
🔇 osh × 2Kanal bir marta ulandi, «Ovozsiz» uni uzmadi, xabar esa eng so'nggi muted bilan () chiqdi. Effekt hodisasi argument ham oladi (text) — u oddiy funksiya kabi chaqiriladi. Kanalga onMessage ning o'zi emas, uni chaqiradigan arrow funksiya berildi: effekt hodisasi effekt kodidan tashqariga chiqmadi.
4-mashq: Vazifalar qadami
vazifalar da refactor/effekt-hodisasi branch'ini oching. Avval «Muammo — testda» bo'limidagi testni tekshiruv/App.test.tsx ga qo'shib, uning yiqilishini ko'ring (expected … to have a length of 1 but got 4). Keyin «Tuzatish» dagi o'zgarishni kiriting va test o'tsin.
Yechim
Tekshiruv ro'yxati:
npx vitest run tekshiruv/App.test.tsx— avvalTests 1 failed | 4 passed (5), keyinTests 5 passed (5).- Internet effektining massivi —
[];grep -n "useEffectEvent" src/App.tsx— import va bitta chaqiruv. npm run lint— jim:onlaynBoldimassivda yo'q va faqat effekt ichidan chaqiriladi.- Brauzerda: DevTools → Network → "Offline" ni yoqing va o'chiring — ro'yxat server bilan sinxronlanadi.
Commit — refactor: online tinglovchisi useEffectEvent bilan bir marta ulanadi. PR'ni birlashtiring.
9. Real ishda
- Chat, xarita, real-time panellar — ulanish bir narsaga (xona, foydalanuvchi), xabar ko'rinishi esa boshqa narsalarga (mavzu, ovoz, til) bog'liq bo'lgan har joyda
useEffectEventkerak bo'ladi. - Custom hooklar ichida u ayniqsa foydali: hook tashqaridan ishlovchi (
onMessage) qabul qiladi va har chizishda yangi funksiya kelsa ham qayta ulanmaydi (Custom hooklar I).vazifalardagiuseOynaHodisasihooki shunday quriladi. - Eski loyihalarda "latest ref" naqshi va
useEventnomli o'z hooklari uchraydi — React 19.2 ga o'tganda ularuseEffectEventbilan almashtiriladi. - Intervyu savollari: "
useEffectEventqanday muammoni hal qiladi?", "uni qayerdan chaqirib bo'lmaydi?", "nega uni massivga yozmaymiz?".
Xulosa
- Effekt ichida ikki xil mantiq bor: reaktiv (o'zgarsa — qayta sinxronlash) va reaktiv bo'lmagan (faqat eng so'nggi qiymatni o'qish).
useEffectEvent(fn)reaktiv bo'lmagan qismni ajratadi: eng so'nggi props/state'ni ko'radi, massivga kirmaydi.- Qoidalar: faqat effekt va effekt hodisalari ichidan; chizish paytida emas (
can't be called during rendering); boshqa komponentga berilmaydi. - Linterni jim qilish uchun emas: "qiymat o'zgarsa qayta ulanish kerakmi?" — ha bo'lsa, massivda qolsin.
- React 19.2 (2025-10-01) dan barqaror;
vazifalardaonlinetinglovchisi 4 martadan 1 martaga tushdi (test bilan isbotlandi).
Keyingi dars: Effektda ma'lumot olish va nega bu ko'pincha noto'g'ri — fetch + useEffect ning to'liq shakli: yuklanish, xato, poyga va nega katta ilovalarda kutubxona yoki framework tanlanadi.
Manbalar
- React:
useEffectEvent— react.dev/reference/react/useEffectEvent - React: "Separating Events from Effects" — react.dev/learn/separating-events-from-effects
- React blogi: "React 19.2" (2025-10-01) —
useEffectEventbarqaror API sifatida — react.dev/blog/2025/10/01/react-19-2
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!