10-bo‘lim
Yon ta'sirlar - useEffect
useEffect qachon ishlaydi, bog'liqliklar ro'yxati, tozalash funksiyasi, cheksiz sikl sabablari va effekt kerak bo'lmagan holatlar.
Ushbu bo‘lim mundarijasi
Komponentning asosiy vazifasi - chizish. Lekin ba'zan undan tashqarida ish qilish kerak bo'ladi: obuna bo'lish, taymer qo'yish, sarlavhani o'zgartirish.
Bunday ishlar yon ta'sir deb ataladi va ular uchun
useEffect bor.
Birinchi effekt #
import { useState, useEffect } from "react";
import { chiz, bos, matn } from "./dom-muhit.mjs";
const izlar = [];
function Kuzatuvchi() {
const [soni, ozgartir] = useState(0);
izlar.push(`chizildi: ${soni}`);
useEffect(() => {
izlar.push(`effekt ishladi: ${soni}`);
});
return <button onClick={() => ozgartir(soni + 1)}>Soni: {soni}</button>;
}
await chiz(<Kuzatuvchi />);
await bos("button");
console.log(izlar.join("\n"));
chizildi: 0
effekt ishladi: 0
chizildi: 1
effekt ishladi: 1
Tartibga e'tibor bering: avval chizish, keyin effekt.
React avval ekranni yangilaydi, shundan keyingina effektni chaqiradi. Shuning uchun effekt ichida DOM allaqachon tayyor bo'ladi.
Bog'liqliklar ro'yxati #
import { useState, useEffect } from "react";
import { chiz, bos } from "./dom-muhit.mjs";
const izlar = [];
function Uch() {
const [a, aniOzgartir] = useState(0);
const [b, bniOzgartir] = useState(0);
useEffect(() => {
izlar.push("har chizishda");
});
useEffect(() => {
izlar.push("faqat bir marta");
}, []);
useEffect(() => {
izlar.push(`a o'zgardi: ${a}`);
}, [a]);
return (
<div>
<button id="a" onClick={() => aniOzgartir(a + 1)}>A</button>
<button id="b" onClick={() => bniOzgartir(b + 1)}>B</button>
</div>
);
}
await chiz(<Uch />);
izlar.push("--- A bosildi ---");
await bos("#a");
izlar.push("--- B bosildi ---");
await bos("#b");
console.log(izlar.join("\n"));
har chizishda
faqat bir marta
a o'zgardi: 0
--- A bosildi ---
har chizishda
a o'zgardi: 1
--- B bosildi ---
har chizishda
Uch xil xatti-harakat aniq ko'rindi:
| Yozuv | Qachon ishlaydi |
|---|---|
useEffect(f) | Har chizishdan keyin |
useEffect(f, []) | Faqat birinchi marta |
useEffect(f, [a]) | a o'zgarganda |
B bosilganda a o'zgarmadi - shuning uchun uchinchi effekt
ishlamadi.
Bu farqni yaxshi yodda tuting:
useEffect(f); // har chizishda - odatda XATO
useEffect(f, []); // bir marta
Massivni unutish eng ko'p uchraydigan xatolardan biri. Agar effekt ichida holat o'zgartirilsa, u cheksiz siklga aylanadi:
chizish → effekt → holat o'zgardi → chizish → effekt → ...
Shuning uchun useEffect yozganda har doim bog'liqliklarni
ochiq ko'rsating.
Tozalash #
import { useState, useEffect } from "react";
import { chiz, bos } from "./dom-muhit.mjs";
const izlar = [];
function Obuna({ kanal }) {
useEffect(() => {
izlar.push(`obuna: ${kanal}`);
return () => {
izlar.push(`obuna bekor: ${kanal}`);
};
}, [kanal]);
return <p>Kanal: {kanal}</p>;
}
function Sahifa() {
const [kanal, ozgartir] = useState("birinchi");
return (
<div>
<button onClick={() => ozgartir("ikkinchi")}>Almashtirish</button>
<Obuna kanal={kanal} />
</div>
);
}
await chiz(<Sahifa />);
await bos("button");
await chiz(<div />);
console.log(izlar.join("\n"));
obuna: birinchi
obuna bekor: birinchi
obuna: ikkinchi
obuna bekor: ikkinchi
Effekt funksiya qaytarishi mumkin - u tozalovchi.
U ikki holatda chaqiriladi:
- Effekt qayta ishlashidan oldin (bog'liqlik o'zgarganda);
- Komponent yo'q qilinganda.
Tartibga e'tibor bering: yangi obuna boshlanishidan oldin eskisi bekor qilindi.
Tozalash ixtiyoriy emas. Quyidagilarni ochgan bo'lsangiz, albatta yoping:
| Ochilgan | Tozalash |
|---|---|
setInterval | clearInterval |
setTimeout | clearTimeout |
addEventListener | removeEventListener |
| WebSocket ulanishi | close() |
| Obuna | Bekor qilish |
Tozalamasangiz, komponent yo'qolgandan keyin ham taymer ishlayveradi va yo'q komponentning holatini o'zgartirmoqchi bo'ladi.
Bu sekin, lekin barqaror xotira oqishi. Bir sahifada odam uzoq o'tirsa, ilova asta-sekin sekinlashadi.
Taymer misoli #
import { useState, useEffect } from "react";
import { chiz } from "./dom-muhit.mjs";
const izlar = [];
function Soat({ ishlaydimi }) {
const [tik, ozgartir] = useState(0);
useEffect(() => {
if (!ishlaydimi) return;
izlar.push("taymer qo'yildi");
const id = setInterval(() => ozgartir((o) => o + 1), 1000);
return () => {
izlar.push("taymer tozalandi");
clearInterval(id);
};
}, [ishlaydimi]);
return <p>Tik: {tik}</p>;
}
await chiz(<Soat ishlaydimi={true} />);
await chiz(<Soat ishlaydimi={false} />);
await chiz(<div />);
console.log(izlar.join("\n"));
taymer qo'yildi
taymer tozalandi
ishlaydimi false bo'lganda effekt darhol qaytdi - taymer
qo'yilmadi, lekin eskisi tozalandi.
Aniq vaqt chiqarilmadi, chunki u har ishga tushirishda boshqacha bo'lardi.
Cheksiz sikl #
import { useState, useEffect } from "react";
import { chiz } from "./dom-muhit.mjs";
let chizishlar = 0;
function Xavfsiz() {
const [malumot, ozgartir] = useState(null);
chizishlar += 1;
useEffect(() => {
ozgartir({ yuklandi: true });
}, []);
return <p>{malumot ? "yuklandi" : "kutilmoqda"}</p>;
}
await chiz(<Xavfsiz />);
console.log("chizishlar soni:", chizishlar);
console.log("holat:", document.querySelector("p").textContent);
chizishlar soni: 2
holat: yuklandi
Ikki chizish bo'ldi: birinchisi boshlang'ich holat bilan, ikkinchisi effekt holatni o'zgartirgandan keyin.
Bog'liqliklar Object.is bilan solishtiriladi, ya'ni obyektlar
havola bo'yicha.
const sozlama = { sahifa: 1 }; // har chizishda YANGI obyekt
useEffect(() => {
// ...
}, [sozlama]); // har doim "o'zgargan"
Har chizishda yangi obyekt yaratiladi, React uni yangi deb biladi, effekt ishlaydi, holat o'zgaradi, yana chizish...
Yechimlar:
- Bog'liqlikka oddiy qiymat bering:
[sozlama.sahifa]. - Obyektni komponentdan tashqarida e'lon qiling.
useMemobilan eslab qoling (17-bo'lim).
Xuddi shu muammo funksiyalarda ham bor - ular ham har chizishda yangi yaratiladi.
Effekt kerak bo'lmagan holatlar #
import { useState, useEffect } from "react";
import { chiz, yoz, matn } from "./dom-muhit.mjs";
function Yomon({ ism, familiya }) {
const [toliq, ozgartir] = useState("");
useEffect(() => {
ozgartir(`${ism} ${familiya}`);
}, [ism, familiya]);
return <p id="yomon">{toliq}</p>;
}
function Yaxshi({ ism, familiya }) {
const toliq = `${ism} ${familiya}`;
return <p id="yaxshi">{toliq}</p>;
}
await chiz(
<div>
<Yomon ism="Malika" familiya="Karimova" />
<Yaxshi ism="Malika" familiya="Karimova" />
</div>,
);
console.log("effekt bilan:", matn("#yomon"));
console.log("to'g'ridan-to'g'ri:", matn("#yaxshi"));
effekt bilan: Malika Karimova
to'g'ridan-to'g'ri: Malika Karimova
Natija bir xil, lekin Yomon ikki marta chizildi va ortiqcha
holat saqladi.
Bu eng ko'p uchraydigan ortiqcha ishlatish:
| Vazifa | To'g'ri yo'l |
|---|---|
| Props dan qiymat hisoblash | Chizish paytida hisoblang |
| Hodisaga javob berish | Hodisa ishlovchisida |
| Holatni props dan olish | Odatda umuman kerak emas |
| Ro'yxatni filtrlash | Chizish paytida |
useEffect faqat tashqi dunyo bilan bog'lanish uchun:
tarmoq, taymer, brauzer API si, uchinchi tomon kutubxonasi.
Oddiy tekshiruv: "bu ish React dan tashqarida biror narsaga tegadimi?" Javob yo'q bo'lsa, effekt kerak emas.
Tugma bosilganda so'rov yuborish kerak bo'lsa - buni ishlovchida qiling, effektda emas.
Bog'liqliklarni to'g'ri yozish #
import { useState, useEffect } from "react";
import { chiz, bos } from "./dom-muhit.mjs";
const izlar = [];
function Hisobot({ guruh }) {
const [sahifa, ozgartir] = useState(1);
useEffect(() => {
izlar.push(`so'rov: guruh=${guruh}, sahifa=${sahifa}`);
}, [guruh, sahifa]);
return (
<button onClick={() => ozgartir(sahifa + 1)}>
Keyingi sahifa
</button>
);
}
await chiz(<Hisobot guruh="A1" />);
await bos("button");
await chiz(<Hisobot guruh="B2" />);
console.log(izlar.join("\n"));
so'rov: guruh=A1, sahifa=1
so'rov: guruh=A1, sahifa=2
so'rov: guruh=B2, sahifa=2
Effekt ichida ishlatilgan hamma o'zgaruvchi bog'liqliklarga kirishi kerak.
Bittasini tushirib qoldirsangiz, effekt eski qiymat bilan ishlaydi va xato jimgina sodir bo'ladi.
eslint-plugin-react-hooks buni avtomatik tekshiradi - uni
albatta o'rnating.
- Effekt chizishdan keyin ishlashini isbotlang.
- Uch xil bog'liqliklar ro'yxatini solishtiring.
- Massivni unutib, cheksiz sikl yasab ko'ring.
- Tozalovchi funksiya qaytaring.
setIntervalqo'yib, uni tozalang.- Tozalashni olib tashlab, oqibatini o'ylang.
- Obyektni bog'liqlik qilib, muammoni ko'ring.
- Uni oddiy qiymatga almashtiring.
- Props dan hisoblash uchun effekt yozib, keyin olib tashlang.
eslint-plugin-react-hooksni o'rnating.
Xulosa #
useEffectchizishdan keyin ishlaydi - DOM tayyor bo'ladi.- Bog'liqliklar: massivsiz - har chizishda,
[]- bir marta,[a]-ao'zgarganda. - Effekt tozalovchi funksiya qaytarishi mumkin; u qayta ishlashdan oldin va yo'q qilishda chaqiriladi.
- Ochilgan narsani albatta yoping - aks holda xotira oqadi.
- Obyekt yoki funksiya bog'liqlik cheksiz siklga olib keladi.
useEffectfaqat tashqi dunyo uchun; hisoblash va hodisalar uchun emas.- Effekt ichidagi hamma o'zgaruvchi bog'liqliklarda bo'lsin.
Keyingi bo'limda ma'lumot olishni o'rganamiz.
O‘qish tarixini saqlamoqchimisiz?
Tizimga kirsangiz, tugatgan bo‘limlaringiz saqlanadi va qoldirgan joyingizdan davom etasiz.
Xatolik topdingizmi?
Imlo xatosi, ishlamaydigan kod yoki noto‘g‘ri ma‘lumotni ko‘rsangiz - bizga xabar bering. Har bir xabar administrator tomonidan ko‘rib chiqiladi.