Mundarija (28)
- Bu darsda
- 1. Nega bu kerak?
- 2. Yon ta'sir uchun uch joy
- 2.1 Chizish, hodisa, effekt
- 2.2 Birinchi effekt
- 3. Effekt qachon ishlaydi
- 3.1 Render → Commit → Effekt
- 3.2 Har chizishdan keyin — sukut bo'yicha
- 4. "Tashqi tizim" nima
- 4.1 Effektning asosiy vazifasi
- 4.2 localStorage bilan sinxronlash
- 5. Cheksiz sikl tuzog'i
- 5.1 Effekt ichida state
- 5.2 Saqlagichsiz — o'lchov
- 5.3 Qanday tuzatiladi
- 6. Vazifalar qadami: holat React'ga, birinchi effekt
- 6.1 Reja
- 6.2 Holat — App ning state'i
- 6.3 localStorage — effekt
- 7. Ko'p uchraydigan xatolar
- 8. Mashqlar
- 1-mashq (oson): tartibni ayting
- 2-mashq (o'rta): tilni eslab qolish
- 3-mashq (qiyin): ortiqcha state va effekt
- 4-mashq: Vazifalar qadami
- 9. Real ishda
- Xulosa
- Manbalar
useEffect I: effekt — React'dan tashqaridagi tizim bilan sinxronlash
Qisqacha:
useEffect(() => { … })— React chizishni tugatib, DOM'ni yangilagandan keyin ishlaydigan kod. U komponentni React boshqarmaydigan narsa — tashqi tizim bilan sinxronlash uchun: sahifa sarlavhasi (document.title),localStorage, taymer, server, brauzer hodisalari. Komponent funksiyasi (chizish) toza bo'lishi kerak, shuning uchun yon ta'sirlar u yerda emas, effektda yoki hodisa ishlovchisida bo'ladi. Ikkinchi argument — bog'liqliklar massivi:[cart]bo'lsa, effekt faqatcarto'zgarganda qayta ishlaydi. Eng katta tuzoq — effekt ichida state'ni shartsiz o'zgartirish: bu cheksiz siklga olib keladi.
Bu darsda
- Yon ta'sir uchun uchta joyni ajrata olasiz: chizish, hodisa ishlovchisi va effekt.
useEffectqachon ishlashini — Render → Commit → Effekt tartibini — konsolda o'z ko'zingiz bilan ko'rasiz.- "Tashqi tizim" nima ekanini va qachon effekt kerakligini tushuntira olasiz.
document.titlevalocalStorageni state bilan sinxronlaysiz.- Cheksiz sikl tuzog'ini taniysiz va uni xavfsiz ko'rasiz.
Oldin bilishingiz kerak: Hooklar qoidalari, Pure komponentlar va render qoidasi, Pure funksiya va side effect, localStorage va sessionStorage.
1. Nega bu kerak?
Jasur aka yangi talab bilan keldi: "Mehmon brauzerda o'nta tab ochib qo'ygan bo'ladi. Savatda nechta taom borligi tab nomida ko'rinsin — (3) Bahor." Tab nomi — document.title (Brauzer muhiti: window va document darsidan tanish).
Sardor buni komponentning o'ziga yozdi:
function Cart() {
const [count, setCount] = useState(0);
document.title = `(${count}) Bahor`; // ❌ chizish paytida
return <button onClick={() => setCount(count + 1)}>Savatga</button>;
}Ishlaydi. Lekin Pure komponentlar darsidagi qoidani eslang: komponent — toza funksiya. Bir xil props va state — bir xil JSX, hech qanday yon ta'sirsiz. document.title = … — yon ta'sir: u funksiyadan tashqaridagi dunyoni o'zgartiradi. React komponentni istagan paytda, istagan marta chaqirishi mumkin. StrictMode dev'da uni ataylab ikki marta chaqiradi. Kelajakdagi React imkoniyatlari esa chizishni boshlab, ekranga chiqarmasdan tashlab yuborishi ham mumkin (Concurrent rendering darsida). Shunda sarlavha ekranda yo'q holatni ko'rsatib qoladi.
Vanilla JavaScript'da bu muammo yo'q edi: vazifalar v6 da render() funksiyasini o'zimiz chaqirardik va "chizishdan keyin" qatorini o'zimiz yozardik. React'da chizishni React chaqiradi. Unga "chizib bo'lgach, mana shuni ham qil" deyishning yo'li kerak. Bu yo'l — effekt.
Hayotiy o'xshatish: restoranda oshpaz taomni tayyorlaydi (chizish), ofitsiant uni stolga qo'yadi (DOM yangilanishi). Shundan keyin administrator kassadagi "band stollar" taxtasini yangilaydi. Taxta — oshxonadan tashqaridagi tizim. Uni taom tayyorlanayotganda emas, stolga qo'yilgandan keyin yangilash kerak — aks holda taom yonib ketsa, taxta yolg'on gapiradi.
2. Yon ta'sir uchun uch joy
2.1 Chizish, hodisa, effekt
Komponent ichidagi kod uch xil joyda yashaydi:
| Joy | Qachon ishlaydi | Nima uchun |
|---|---|---|
| Komponent tanasi (chizish) | har chizishda | JSX hisoblash — faqat toza kod |
Hodisa ishlovchisi (onClick) |
foydalanuvchi bosganda | harakat natijasidagi yon ta'sir |
Effekt (useEffect) |
chizish ekranga chiqqandan keyin | chizish natijasidagi sinxronlash |
Hodisa ishlovchisini Hodisalarni boshqarish darsida ko'rdik: "Saqlash bosildi — serverga yubor". Yon ta'sirning sababi aniq bitta harakat. Effekt esa boshqa savolga javob beradi: "ekranda shu narsa ko'rinayotgan ekan, tashqi dunyo ham unga mos bo'lsin". Sabab — harakat emas, holatning o'zi.
Tab nomi aynan ikkinchi turdagi vazifa. Savatdagi son qayerdan o'zgarmasin — tugma, server, boshqa tab — tab nomi doim unga mos bo'lishi kerak.
Yon ta'sir (side effect) — funksiyaning o'zidan tashqaridagi narsani o'zgartirishi (Pure funksiya va side effect darsida). Effekt (effect) — React'da chizish natijasida bajariladigan yon ta'sir: useEffect ga berilgan funksiya.
2.2 Birinchi effekt
import { useEffect, useState } from "react";
function App() {
const [count, setCount] = useState(0);
useEffect(() => {
document.title = `(${count}) Bahor`;
console.log("effekt:", document.title);
});
return <button onClick={() => setCount(count + 1)}>Savatga</button>;
}Konsolda:
effekt: (0) Bahor
effekt: (1) Bahor
effekt: (2) BahorBlok tugmani ikki marta o'zi bosadi. Uch qator — uch chizish: birinchisi ochilganda, keyingi ikkitasi har bosishdan keyin. Effekt har chizishdan keyin ishladi va sarlavhani yangi count ga moslashtirdi.
useEffect ning tuzilishi:
import { useEffect } from "react"—useStatebilan bir joydan;- birinchi argument — funksiya. React uni o'zi, keyinroq chaqiradi. Uni effektning "setup" (sozlash) funksiyasi deyishadi;
useEffect— hook, demak hooklar qoidalari unga ham tegishli: yuqori darajada, shartsiz.
Effekt funksiyasi count ni qayerdan oladi? Odatdagi closure orqali: u shu chizishning count ini ko'radi. Har chizishda yangi funksiya — yangi count bilan.
Tekshirib ko'ring: Nega
useEffect(document.title = "…")deb yozib bo'lmaydi? Nega aynan funksiya kerak?
Javob
useEffect(document.title = "…") da tenglik darhol, chizish paytida bajariladi — useEffect ga esa natija (satr) boriladi. Funksiya berilganda biz kodni o'zimiz bajarmaymiz, balki React'ga "keyinroq shuni chaqir" deb topshiramiz. Bu Callback g'oyasi: addEventListener("click", fn) da ham fn() emas, fn berilardi.
3. Effekt qachon ishlaydi
3.1 Render → Commit → Effekt
Effekt chizish paytida emas, keyin ishlaydi. Buni sinab ko'ramiz: komponent <h1 id="title"> qaytaradi. Chizish paytida ham, effektda ham DOM'dan shu elementni qidiramiz:
import { useEffect } from "react";
function App() {
const found = document.getElementById("title");
console.log("1. render: h1 DOM'da bormi?", found !== null);
useEffect(() => {
const el = document.getElementById("title");
console.log("3. effekt: h1 DOM'da bormi?", el !== null);
console.log(" matni:", el.textContent);
});
console.log("2. render tugadi, JSX qaytadi");
return <h1 id="title">Bahor menyusi</h1>;
}Konsolda:
1. render: h1 DOM'da bormi? false
2. render tugadi, JSX qaytadi
3. effekt: h1 DOM'da bormi? true
matni: Bahor menyusiuseEffect qatori 1 va 2 orasida turibdi, lekin uning ichidagi kod uchinchi bo'lib ishladi. Chizish paytida <h1> hali DOM'da yo'q: komponent JSX'ni endi qaytarmoqchi. Effekt ishlaganda esa React elementni allaqachon sahifaga qo'ygan.
Bu orada nima bo'ldi? React'ning ishi uch bosqichda:
| Bosqich | Kim ishlaydi | Nima bo'ladi | DOM |
|---|---|---|---|
| Render (chizish) | sizning komponentingiz | JSX hisoblanadi | hali eski |
| Commit | React DOM | farqlar DOM'ga yoziladi | yangi |
| Effekt | sizning useEffect ingiz |
tashqi tizim moslashtiriladi | yangi, ekranda |
| Cleanup | effekt qaytargan funksiya | oldingi effekt tozalanadi — useEffect III da | — |
Commit (commit) — React chizish natijasini haqiqiy DOM'ga yozadigan bosqich. Nomi Git'dagi commit bilan bir xil ma'noda: "o'zgarishlarni qayd etish". Commit'dan keyin brauzer ekranni chizadi (paint), shundan keyin effektlar ishlaydi. Bosqichlarning ichki ishlashi — Render va commit darsida chuqur.
flowchart LR
T["setCount: state o'zgardi"] --> R["Render: App() chaqiriladi"]
R --> C["Commit: DOM yangilanadi"]
C --> P["Brauzer ekranni chizadi"]
P --> E["Effekt: useEffect funksiyasi"]
E -. "setState bo'lsa" .-> RDiagrammadagi uzuq chiziqqa e'tibor bering: effekt ichida state o'zgartirilsa, zanjir boshidan yana boshlanadi. «Cheksiz sikl» bo'limida shu chiziq muammoga aylanadi.
Maslahat: Effekt brauzer ekranni chizgandan keyin ishlagani uchun foydalanuvchini kuttirmaydi. Juda kam hollarda (o'lcham olib, joylashuvni darhol tuzatish) chizishdan oldin ishlash kerak bo'ladi — buning uchun
useLayoutEffectbor (useLayoutEffect darsida).
3.2 Har chizishdan keyin — sukut bo'yicha
Ikkinchi argumentsiz effekt har chizishdan keyin ishlaydi — «Birinchi effekt» bo'limida uch marta ishlaganini ko'rdik. Ko'pincha bu ortiqcha. Tab nomi faqat count o'zgarganda yangilansa yetadi. Komponentda boshqa state ham bo'lishi mumkin — masalan, qidiruv maydoni. Har harfda tab nomini qayta yozish keraksiz ish.
Ikkinchi argument — bog'liqliklar massivi (dependency array): effekt ishlatadigan va o'zgarishi mumkin bo'lgan qiymatlar ro'yxati. React har chizishdan keyin massivdagi qiymatlarni oldingi chizishdagisi bilan solishtiradi. Birortasi o'zgargan bo'lsa — effekt ishlaydi, aks holda — o'tkazib yuboriladi:
import { useEffect, useState } from "react";
function App() {
const [count, setCount] = useState(0);
const [query, setQuery] = useState("");
useEffect(() => {
document.title = `(${count}) Bahor`;
console.log("effekt:", document.title);
}, [count]);
console.log("render, query =", query);
return (
<div>
<input
placeholder="Qidiruv"
value={query}
onChange={(e) => setQuery(e.target.value)}
/>
<button onClick={() => setCount(count + 1)}>Savatga</button>
</div>
);
}Konsolda:
render, query =
effekt: (0) Bahor
render, query = osh
render, query = osh
effekt: (1) BahorUch chizish, lekin effekt ikki marta. Qidiruvga yozilganda (query o'zgardi) — count o'sha 0, effekt o'tkazib yuborildi. Tugma bosilganda count 1 bo'ldi — effekt ishladi. Massivning uch shakli bor:
| Yozuv | Effekt qachon ishlaydi |
|---|---|
| massivsiz | har chizishdan keyin |
[count] |
birinchi chizishda va count o'zgarganda |
[] |
faqat birinchi chizishda |
Bu jadval — boshlanishi. Solishtirish qanday ishlashi, massivga nima yozish kerakligi va nima uchun uni "aldash" xavfli — keyingi dependency massivi darsining butun mavzusi. Bugun bitta qoida yetadi: effekt ishlatgan, o'zgaradigan har qiymat massivda bo'lsin.
4. "Tashqi tizim" nima
4.1 Effektning asosiy vazifasi
React hujjati effektni bir jumla bilan ta'riflaydi: "effektlar komponentni tashqi tizim bilan sinxronlash uchun". Tashqi tizim (external system) — React boshqarmaydigan, lekin komponent holatiga mos bo'lishi kerak bo'lgan har narsa.
| Tashqi tizim — effekt kerak | Tashqi emas — effekt kerak emas |
|---|---|
document.title, <html lang> |
boshqa state'dan hisoblanadigan qiymat |
localStorage, sessionStorage |
props'dan hisoblanadigan qiymat |
setInterval, setTimeout |
tugma bosilgandagi ish (ishlovchi bor) |
server ulanishi, WebSocket |
ro'yxatni filtrlash, saralash |
window hodisalari (online, resize) |
JSX ichidagi matn va class |
| boshqa kutubxona vidjeti (xarita, grafik) | boshqa komponentning state'i |
Chap ustundagilarning umumiy jihati: ular React'dan oldin ham bor edi va React ularning "ichiga" kira olmaydi. React <h1> ni o'zi yaratadi va boshqaradi. document.title esa <head> da, React daraxtidan tashqarida. localStorage — umuman DOM emas. Bunday narsalarga React'ning holatini sinxronlash — effektning ishi.
O'ng ustundagilar uchun effekt — ortiqcha va ko'pincha zararli. Bu shunchalik keng tarqalgan xatoki, unga alohida dars ajratilgan: Sizga effekt kerak emas.
4.2 localStorage bilan sinxronlash
Savat sahifa yangilanganda yo'qolmasin. Ikki ish bor: ochilganda — o'qish, o'zgarganda — yozish.
import { useEffect, useState } from "react";
function App() {
// O'qish — bir marta, birinchi chizishda (lazy boshlang'ich qiymat)
const [cart, setCart] = useState(() => {
const saved = localStorage.getItem("bahor:savat");
return saved === null ? [] : JSON.parse(saved);
});
// Yozish — har o'zgarishdan keyin: tashqi tizim cart'ga ergashadi
useEffect(() => {
localStorage.setItem("bahor:savat", JSON.stringify(cart));
console.log("saqlandi:", localStorage.getItem("bahor:savat"));
}, [cart]);
const add = (dish) => setCart([...cart, dish]);
return (
<div>
<p>Savatda: {cart.join(", ") || "bo'sh"}</p>
<button onClick={() => add("Osh")}>Osh +</button>{" "}
<button onClick={() => add("Choy")}>Choy +</button>
</div>
);
}Konsolda:
saqlandi: []
saqlandi: ["Osh"]
saqlandi: ["Osh","Choy"]Ekranda:
Savatda: Osh, Choy
Osh + Choy +Ikki qism ikki xil joyda. O'qish — useState ga berilgan funksiyada (useState darsidagi lazy boshlang'ich qiymat). U faqat birinchi chizishda ishlaydi va natija darhol state bo'ladi. Effekt bilan o'qisak, birinchi chizish bo'sh savat bilan chiqib, keyin "sakrardi". Yozish — effektda, chunki u savatdagi har o'zgarishga ergashishi kerak.
Nega yozishni har tugmaning onClick iga qo'ymadik? Qo'ysa ham bo'lardi. Lekin savat o'nta joydan o'zgarsa — o'nta joyda setItem yozish va birortasini unutmaslik kerak. Effektda esa qoida bitta: "cart qanday bo'lsa, localStorage da ham shunday". Qayerdan o'zgargani muhim emas.
Tekshirib ko'ring: Konsoldagi birinchi
saqlandi: []qatori nega chiqdi? Hech kim hech narsa bosmagan-ku.
Javob
[cart] massivli effekt birinchi chizishdan keyin ham ishlaydi — jadvaldagi "birinchi chizishda va o'zgarganda". Birinchi chizishda React solishtiradigan "oldingi qiymat" yo'q, shuning uchun effekt doim bir marta ishlaydi. Bu yerda bu zararsiz: localStorage dagi qiymat o'zi bilan qayta yozildi.
5. Cheksiz sikl tuzog'i
5.1 Effekt ichida state
Sardor "sahifa necha marta ko'rildi" hisoblagichini yozmoqchi bo'ldi. Mantiq: "har chizishdan keyin bittaga oshir". Diagrammadagi uzuq chiziqni eslang: effekt state'ni o'zgartirsa, yangi chizish boshlanadi. Chizishdan keyin effekt yana ishlaydi, yana state o'zgaradi… Bu — cheksiz sikl.
Brauzerni qotirmaslik uchun quyidagi blokda saqlagich bor: modul o'zgaruvchisi effektni beshinchi marta ishlagandan keyin to'xtatadi. Haqiqiy kodda bunday saqlagich bo'lmaydi.
import { useEffect, useState } from "react";
let runs = 0; // saqlagich — faqat dars uchun
function App() {
const [views, setViews] = useState(0);
useEffect(() => {
runs++;
if (runs > 5) return; // ⛔ saqlagich: 5 dan keyin to'xta
console.log(`effekt ${runs}: views = ${views}`);
setViews(views + 1); // ❌ state o'zgaradi → yana chizish
});
return <p>Ko'rildi: {views}</p>;
}Konsolda:
effekt 1: views = 0
effekt 2: views = 1
effekt 3: views = 2
effekt 4: views = 3
effekt 5: views = 4Ekranda:
Ko'rildi: 5Bitta ochilishda besh "ko'rish" — saqlagich bo'lmaganda esa son to'xtovsiz o'sardi. Har qadam:
| Qadam | views |
Nima bo'ldi |
|---|---|---|
| 1-chizish | 0 | effekt → setViews(1) |
| 2-chizish | 1 | effekt → setViews(2) |
| 3-chizish | 2 | effekt → setViews(3) |
| … | … | to'xtamaydi |
5.2 Saqlagichsiz — o'lchov
Xuddi shu kodni saqlagichsiz Chrome 154 da (React 19.3.0 dev, sayt oynasidagi o'sha to'plam) 2 soniya ishlatib ko'rdik. Uch o'lchov:
2 s ichida: 2 861 / 2 962 / 4 610 marta chizildi
konsolda: 55 / 66 / 88 marta qizil xato
Maximum update depth exceeded. This can happen when a component calls setState inside useEffect, but useEffect either doesn't have a dependency array, or one of the dependencies changes on every render.Soniyasiga 1 400–2 300 marta chizish va protsessor to'liq band. "Yangilanish chuqurligi oshib ketdi. Komponent useEffect ichida setState chaqirsa, useEffect esa bog'liqliklar massivisiz bo'lsa yoki bog'liqliklaridan biri har chizishda o'zgarsa, shunday bo'ladi." React sababni aniq aytyapti — va sikl to'xtamaydi, faqat ogohlantiradi. Sahifa qotadi, telefon qiziydi.
5.3 Qanday tuzatiladi
Uchta savol bering:
- Bu state'ga umuman effekt kerakmi? Ko'pincha yo'q. "Ko'rishlar soni" server hisoblaydigan narsa, hisoblanadigan qiymat esa renderda hisoblanadi (Sizga effekt kerak emas).
- Massiv bormi?
useEffect(fn)massivsiz — har chizishda.[]yoki[id]— faqat kerak bo'lganda. - Effekt o'zi o'zgartirgan qiymatga bog'liq emasmi?
[views]massivi bilansetViews(views + 1)— yana sikl: effektviewsni o'zgartiradi,viewso'zgargani uchun effekt qayta ishlaydi.
ESLint bu siklni kod yozayotganda ko'radi. Saqlagichsiz Views komponentini (useEffect(() => { setViews(views + 1); })) plagin 7.1.1 bilan tekshirdik — ikki xabar keldi (qisqartirildi):
5:3 warning React Hook useEffect contains a call to 'setViews'. Without a list of dependencies, this can lead to an infinite chain of updates. To fix this, pass [views] as a second argument to the useEffect Hook react-hooks/exhaustive-deps
6:5 error Error: Calling setState synchronously within an effect can trigger cascading renders
…
> 6 | setViews(views + 1);
| ^^^^^^^^ Avoid calling setState() directly within an effectBirinchisi: "useEffect ichida setViews chaqirilgan. Bog'liqliklar ro'yxatisiz bu cheksiz yangilanishlar zanjiriga olib kelishi mumkin. [views] ni ikkinchi argument qilib bering." Ehtiyot bo'ling: bu maslahatni ko'r-ko'rona bajarsangiz, uchinchi savoldagi holat — [views] bilan ham sikl. Ikkinchisi — set-state-in-effect qoidasi, error darajasida: "Effekt ichida setState ni sinxron chaqirish zanjirli qayta chizishlarga olib keladi. Effekt tashqi tizimni yangilashi yoki unga obuna bo'lishi kerak." Bu qoida React Compiler qoidalari bilan birga keldi — biz ham aynan shuni aytyapmiz. vazifalar da ham u yoqiq: eslint.config.js dagi reactHooks.configs.flat.recommended uni error qilib ulaydi. Shuning uchun keyingi darslarda kanon effektlarida set… faqat tashqi tizim javob bergandan keyin chaqiriladi, effekt tanasida darhol emas.
Shuni yodda tuting: effekt tashqi tizimni React'ga moslashtiradi. Effekt ichida React state'ini o'zgartirish — "tashqaridan javob keldi" (masalan, server javobi) bo'lgandagina o'rinli. O'shanda ham bir marta, sikl yaratmasdan.
6. Vazifalar qadami: holat React'ga, birinchi effekt
6.1 Reja
Mini-ilova darsida vazifalar ning butun interfeysi React'ga o'tgan edi. Lekin holat hali vanilla do'konda edi: holat.ts dagi obyekt, asosiy.ts dagi obunalar va render.tsx ko'prigi. Har o'zgarishda do'kon xabar berardi, render() esa App ni yangi props bilan flushSync orqali chizardi. Tashqi tizimlar — localStorage, boshqa tablar, server, URL, internet — asosiy.ts da vanilla tinglovchilar edi.
Endi shu uchta darsda (shu dars, useEffect II va useEffect III) holat App ning state'iga, tashqi tizimlar esa effektlarga ko'chadi. Kanonda bu bitta commit — biz uni uch darsga bo'lib o'qiymiz. Yangi branch: refactor/effektlar. Bugun — holat va birinchi effekt. Bog'liqliklarni keyingi darsda tahlil qilamiz, commit, testlar va brauzer tekshiruvi esa useEffect III darsi oxirida.
6.2 Holat — App ning state'i
main.tsx endi butun ilovaning kirish nuqtasi. U boshlang'ich ro'yxatni localStorage dan bir marta o'qib, App ga props qilib beradi:
flushSync(() => {
createRoot(ildiz).render(
<StrictMode>
<App
boshlangichRoyxat={yukla() ?? boshlangichVazifalar}
qoralama={qoralamaniOl()}
/>
</StrictMode>,
);
});App ichida — oddiy useState:
export function App({ boshlangichRoyxat, qoralama }: Props) {
// useState(boshlang'ich): props faqat BIRINCHI renderda olinadi
const [vazifalar, setVazifalar] = useState(boshlangichRoyxat);
// Funksiya — URL faqat birinchi renderda o'qiladi
const [filtr, setFiltr] = useState<Filtr>(() => filtrniOl());Kanondagi izohlar aynan shunday. Ikkinchi qatorga qarang: filtr URL'dan funksiya orqali o'qiladi — «localStorage bilan sinxronlash» bo'limidagi lazy boshlang'ich qiymat. Ro'yxat esa yukla() dan, lekin bu main.tsx da bir marta chaqiriladi va props bo'lib keladi.
6.3 localStorage — effekt
v6 va holat 24 da saqlash har bir o'zgarish yo'lida qo'lda chaqirilardi (asosiy.ts):
// Xotiraga va boshqa tablarga: ro'yxat xabarning o'zida ketadi
function saqlaVaTarqat(): void {
saqla(holat.vazifalar);
tarqat({ tur: OZGARDI, paket: eksportMatni(holat.vazifalar) });
}Endi App.tsx da — bitta effekt (kanon, aynan):
// #26: localStorage — ro'yxat qayerdan o'zgarmasin (forma, server,
// boshqa tab, qaytarish), xotiradagi nusxa unga ergashadi
useEffect(() => {
saqla(vazifalar);
}, [vazifalar]);Izohdagi ro'yxatga qarang: forma, server, boshqa tab, qaytarish (server rad etganda oldingi ro'yxat). To'rt yo'l — bitta effekt. Kanondagi Vitest testi aynan shuni tekshiradi: "effekt: server boshqa ro'yxat bersa — ekran va localStorage". Server boshqa ro'yxat qaytaradi. Testda hech kim saqla ni chaqirmaydi, lekin localStorage.getItem("vazifalar:v3") da serverdagi vazifa paydo bo'ladi.
E'tibor bering: saqlaVaTarqat ikki ishni birga qilardi — saqlash va boshqa tablarga yuborish. Kanonda ular ajraldi: saqlash — effektga, yuborish — hodisa ishlovchisiga qoldi. Nega yuborishni effektga qo'yish xavfli — buni Sizga effekt kerak emas darsida o'lchaymiz (2 soniyada 824 ta xabar).
Diqqat: Bu qadam o'zi alohida commit emas.
asosiy.tsvarender.tsxo'chishi, server va tablar effektlari — keyingi ikki darsda. Kodni shu branch'da yozib boring, tekshiruvni esa useEffect III darsida birga qilamiz.
7. Ko'p uchraydigan xatolar
| Belgi | Sabab | Davosi |
|---|---|---|
Maximum update depth exceeded … inside useEffect |
effektda setState, massivsiz yoki o'zi o'zgartirgan qiymatga bog'liq |
effekt kerakmi? massiv to'g'rimi? |
| birinchi chizishda bo'sh, keyin "sakraydi" | boshlang'ich qiymat effektda o'qilgan | lazy useState(() => …) |
| effekt kutilganidan ko'p ishlaydi | massiv yo'q — har chizishda | [kerakli qiymatlar] |
useEffect(fn()) — effekt ishlamaydi yoki xato |
funksiya o'rniga natija berildi | useEffect(() => { … }) |
document.title ni JSX'da o'zgartirib bo'lmaydi |
<title> — <head> da |
effekt bilan (React 19 dagi <title> — Hujjat metadata darsida) |
Yana bitta xato — effektni "komponent yuklanganda bir marta" deb o'ylash. Effekt chizish natijasiga ergashadi, komponent hayotiga emas. Bu fikr Effekt hayot sikli darsida juda muhim bo'ladi.
8. Mashqlar
Mashqlar kurs/mashqlar/17/26-useeffect-asoslari/ da. Har yechimni «Ishga tushir» bilan sinang.
1-mashq (oson): tartibni ayting
Kodni ishga tushirmasdan, konsolga chiqadigan qatorlar tartibini yozing.
import { useEffect } from "react";
function App() {
console.log("A");
useEffect(() => {
console.log("B");
});
console.log("C");
return <p>Bahor</p>;
}- Birinchi qator:
- Ikkinchi qator:
- Uchinchi qator:
Yechim
Konsolda:
A
C
BA va C — chizish paytida, ketma-ket. useEffect qatori ham chizish paytida bajariladi, lekin u faqat funksiyani ro'yxatga oladi. B ni React commit'dan keyin chaqiradi.
2-mashq (o'rta): tilni eslab qolish
«Bahor» menyusida ikki til tugmasi bor: O'zbekcha va Ruscha. Talablar:
- tanlangan til state'da (
"uz"yoki"ru"), boshlang'ich qiymatilocalStoragedagi"bahor:til"dan (bo'lmasa"uz"); <html lang>atributi doim tanlangan tilga teng (document.documentElement.lang) — bu ekran o'quvchi Malika uchun muhim: u matnni qaysi tilda o'qishni shundan biladi;- tanlov
localStoragega yoziladi; - ekranda
Til: uzyokiTil: ru.
Ikkala tashqi tizim bitta effektda, massiv bilan. Effekt oxirida tekshirish uchun ikkala qiymatni console.log bilan chiqaring: avval lang atributi, keyin localStorage dagi qiymat. Ishora: lazy boshlang'ich qiymat — «localStorage bilan sinxronlash» bo'limida.
Yechim
import { useEffect, useState } from "react";
function App() {
const [lang, setLang] = useState(
() => localStorage.getItem("bahor:til") ?? "uz",
);
useEffect(() => {
document.documentElement.lang = lang;
localStorage.setItem("bahor:til", lang);
const saved = localStorage.getItem("bahor:til");
console.log(document.documentElement.lang, saved);
}, [lang]);
return (
<div>
<p>Til: {lang}</p>
<button onClick={() => setLang("uz")}>O'zbekcha</button>{" "}
<button onClick={() => setLang("ru")}>Ruscha</button>
</div>
);
}Konsolda:
uz uz
ru ruEkranda:
Til: ru
O'zbekcha RuschaIkki tashqi tizim (<html lang> va localStorage) bitta qiymatga — lang ga — ergashadi, shuning uchun bitta effektda. O'zbekcha qayta bosilsa, lang o'zgarmaydi ("uz" → "uz") — React qayta chizmaydi, effekt ham ishlamaydi.
3-mashq (qiyin): ortiqcha state va effekt
Sardor "taomlar soni" va "oxirgi qo'shilgan taom" ni alohida state'da saqlab, ularni effekt bilan to'ldirdi. Konsoldagi har qator — bitta chizish: avval dishes dagi son, keyin summary dagi son.
import { useEffect, useState } from "react";
function App() {
const [dishes, setDishes] = useState([]);
const [summary, setSummary] = useState({ count: 0, last: "" });
useEffect(() => {
setSummary({ count: dishes.length, last: dishes.at(-1) ?? "" });
}, [dishes]);
console.log("chizish:", dishes.length, "ta,", summary.count, "ta");
const add = (dish) => setDishes([...dishes, dish]);
return (
<div>
<p>{summary.count} ta taom, oxirgisi: {summary.last}</p>
<button onClick={() => add("Osh")}>Osh</button>{" "}
<button onClick={() => add("Manti")}>Manti</button>
</div>
);
}Konsolda:
chizish: 0 ta, 0 ta
chizish: 0 ta, 0 ta
chizish: 1 ta, 0 ta
chizish: 1 ta, 1 ta
chizish: 2 ta, 1 ta
chizish: 2 ta, 2 taEkranda:
2 ta taom, oxirgisi: Manti
Osh MantiNatija to'g'ri, lekin konsolga qarang: har bosishda ikki chizish, birinchisida summary eskirgan (1 ta, 0 ta). Bir lahzaga ekranda noto'g'ri son turadi. Vazifa:
- Kodni tuzating: effekt va ortiqcha state qolmasin, har bosishda bitta chizish bo'lsin, ekran o'sha. Ishora: ikkala qiymat ham
dishesdan hisoblanadi — ularni chizish paytida oddiyconstbilan hisoblang (State strukturasini loyihalash darsidagi "hosilaviy qiymat"). - Savol: Sardor ESLint'ni "tinchlantirish" uchun massivga
summaryni ham qo'shsa ([dishes, summary]), nima bo'ladi?
Yechim
import { useState } from "react";
function App() {
const [dishes, setDishes] = useState([]);
// Hosilaviy qiymatlar — chizish paytida, state va effektsiz
const count = dishes.length;
const last = dishes.at(-1) ?? "";
console.log("chizish:", count, "ta");
const add = (dish) => setDishes([...dishes, dish]);
return (
<div>
<p>{count} ta taom, oxirgisi: {last}</p>
<button onClick={() => add("Osh")}>Osh</button>{" "}
<button onClick={() => add("Manti")}>Manti</button>
</div>
);
}Konsolda:
chizish: 0 ta
chizish: 1 ta
chizish: 2 taEkranda:
2 ta taom, oxirgisi: Manti
Osh MantiOlti chizish o'rniga uchta, eskirgan oraliq holat yo'q. summary hech qachon mustaqil qiymat emas edi — u doim dishes dan hisoblanardi.
2-savolga javob: cheksiz sikl. setSummary har safar yangi obyekt beradi. summary massivda bo'lsa, effekt o'zi yaratgan obyekt sababli qayta ishlaydi, yana yangi obyekt beradi — va bu to'xtovsiz takrorlanadi. Bu «Cheksiz sikl tuzog'i» bo'limidagi uchinchi savol. Obyekt nega har safar "yangi" hisoblanishi — keyingi darsda (Object.is).
4-mashq: Vazifalar qadami
vazifalar da refactor/effektlar branch'ini oching. App ga vazifalar state'ini (useState(boshlangichRoyxat)) va localStorage effektini qo'shing — «Vazifalar qadami: holat React'ga, birinchi effekt» bo'limidagidek. main.tsx App ga boshlangichRoyxat={yukla() ?? boshlangichVazifalar} bersin.
Yechim
Tekshiruv ro'yxati (to'liq tekshiruv — useEffect III darsida):
App.tsxdasaqla(vazifalar)faqat bitta joyda — effektda.grep -n "saqla(" src/App.tsx— bitta qator.- Effekt massivi —
[vazifalar]. ESLintexhaustive-depsjim. useState(boshlangichRoyxat)— props faqat birinchi chizishda olinadi. Keyin ro'yxat faqatsetVazifalarorqali o'zgaradi.
9. Real ishda
- Effektlar hamma joyda, lekin kam. Yaxshi yozilgan React ilovada effektlar tashqi tizim chegarasida: analitika, xarita, chat ulanishi,
localStorage, brauzer API'lari.vazifalarda — oltita (kanon):localStorage, boshqa tablar, server, internet, URL,pagehide. document.title— React 19 da<title>ni komponentning o'zida yozish ham mumkin; React uni<head>ga ko'taradi (Hujjat metadata). Boshqa<head>ishlari (masalan,<html lang>) uchun effekt qoladi.- Kod ko'rigida birinchi savol: "bu effekt qaysi tashqi tizim bilan sinxronlaydi?" Javob bo'lmasa, ehtimol effekt keraksiz.
- Intervyu savollari: "
useEffectqachon ishlaydi?" (commit'dan keyin, paint'dan keyin), "massivsiz,[]va[a]farqi?", "effekt ichidasetStateqachon xavfli?".
Xulosa
- Effekt — chizish natijasidagi yon ta'sir:
useEffect(() => { … }, [bog'liqliklar]). - Tartib: Render (komponent chaqiriladi) → Commit (DOM yangilanadi) → ekran → Effekt.
- Effektning vazifasi — React boshqarmaydigan tashqi tizimni (
document.title,localStorage, taymer, server) holatga moslashtirish. - Massivsiz — har chizishdan keyin;
[x]— birinchi chizishda vaxo'zgarganda;[]— bir marta. - Effektda
setState+ noto'g'ri massiv = cheksiz sikl (Maximum update depth exceeded). O'lchandi: 2 s da 2 861–4 610 chizish. vazifalar: holatAppstate'ida,localStorage— bitta effekt,[vazifalar]bilan.
Keyingi dars: useEffect II: dependency massivi chuqur — React massivni qanday solishtirishi (Object.is), obyekt va funksiya bog'liqliklari va ESLint exhaustive-deps.
Manbalar
- React:
useEffect— react.dev/reference/react/useEffect - React: "Synchronizing with Effects" — react.dev/learn/synchronizing-with-effects
- React: "Keeping Components Pure" — react.dev/learn/keeping-components-pure
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!