IlmHamroh
JavaScript Full-stack/17-qism. React asoslari26/45-dars21 daqiqa
Mundarija (28)

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 faqat cart o'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.
  • useEffect qachon ishlashini — Render → Commit → Effekt tartibini — konsolda o'z ko'zingiz bilan ko'rasiz.
  • "Tashqi tizim" nima ekanini va qachon effekt kerakligini tushuntira olasiz.
  • document.title va localStorage ni 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:

jsx
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

jsx
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:

text
effekt: (0) Bahor
effekt: (1) Bahor
effekt: (2) Bahor

Blok 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" — useState bilan 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:

jsx
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:

text
1. render: h1 DOM'da bormi? false
2. render tugadi, JSX qaytadi
3. effekt: h1 DOM'da bormi? true
   matni: Bahor menyusi

useEffect 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" .-> R

Diagrammadagi 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 useLayoutEffect bor (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:

jsx
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:

text
render, query =
effekt: (0) Bahor
render, query = osh
render, query = osh
effekt: (1) Bahor

Uch 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.

jsx
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:

text
saqlandi: []
saqlandi: ["Osh"]
saqlandi: ["Osh","Choy"]

Ekranda:

text
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.

jsx
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:

text
effekt 1: views = 0
effekt 2: views = 1
effekt 3: views = 2
effekt 4: views = 3
effekt 5: views = 4

Ekranda:

text
Ko'rildi: 5

Bitta 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:

text
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:

  1. 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).
  2. Massiv bormi? useEffect(fn) massivsiz — har chizishda. [] yoki [id] — faqat kerak bo'lganda.
  3. Effekt o'zi o'zgartirgan qiymatga bog'liq emasmi? [views] massivi bilan setViews(views + 1) — yana sikl: effekt views ni o'zgartiradi, views o'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):

text
  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 effect

Birinchisi: "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:

tsx
flushSync(() => {
  createRoot(ildiz).render(
    <StrictMode>
      <App
        boshlangichRoyxat={yukla() ?? boshlangichVazifalar}
        qoralama={qoralamaniOl()}
      />
    </StrictMode>,
  );
});

App ichida — oddiy useState:

tsx
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):

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):

tsx
  // #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.ts va render.tsx o'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.

jsx
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:

text
A
C
B

A 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 qiymati localStorage dagi "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 localStorage ga yoziladi;
  • ekranda Til: uz yoki Til: 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
jsx
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:

text
uz uz
ru ru

Ekranda:

text
Til: ru
O'zbekcha Ruscha

Ikki 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.

jsx
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:

text
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 ta

Ekranda:

text
2 ta taom, oxirgisi: Manti
Osh Manti

Natija 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:

  1. Kodni tuzating: effekt va ortiqcha state qolmasin, har bosishda bitta chizish bo'lsin, ekran o'sha. Ishora: ikkala qiymat ham dishes dan hisoblanadi — ularni chizish paytida oddiy const bilan hisoblang (State strukturasini loyihalash darsidagi "hosilaviy qiymat").
  2. Savol: Sardor ESLint'ni "tinchlantirish" uchun massivga summary ni ham qo'shsa ([dishes, summary]), nima bo'ladi?
Yechim
jsx
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:

text
chizish: 0 ta
chizish: 1 ta
chizish: 2 ta

Ekranda:

text
2 ta taom, oxirgisi: Manti
Osh Manti

Olti 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.tsx da saqla(vazifalar) faqat bitta joyda — effektda. grep -n "saqla(" src/App.tsx — bitta qator.
  • Effekt massivi — [vazifalar]. ESLint exhaustive-deps jim.
  • useState(boshlangichRoyxat) — props faqat birinchi chizishda olinadi. Keyin ro'yxat faqat setVazifalar orqali 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. vazifalar da — 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: "useEffect qachon ishlaydi?" (commit'dan keyin, paint'dan keyin), "massivsiz, [] va [a] farqi?", "effekt ichida setState qachon 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 va x o'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: holat App state'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
Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
useEffect I: effekt — React'dan tashqaridagi tizim bilan sinxronlash — IlmHamroh