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.

🕑 11 daqiqa o‘qish 📄 660 so‘z 👁 0 marta ko‘rilgan
Ushbu bo‘lim mundarijasi
  1. Birinchi effekt
  2. Bog'liqliklar ro'yxati
  3. Tozalash
  4. Taymer misoli
  5. Cheksiz sikl
  6. Effekt kerak bo'lmagan holatlar
  7. Bog'liqliklarni to'g'ri yozish
  8. Xulosa

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 #

JSX
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"));
Natija
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 #

JSX
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"));
Natija
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:

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

Bo'sh massiv va massivsiz - butunlay boshqa narsa

Bu farqni yaxshi yodda tuting:

JSX
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 #

JSX
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"));
Natija
obuna: birinchi
obuna bekor: birinchi
obuna: ikkinchi
obuna bekor: ikkinchi

Effekt funksiya qaytarishi mumkin - u tozalovchi.

U ikki holatda chaqiriladi:

  1. Effekt qayta ishlashidan oldin (bog'liqlik o'zgarganda);
  2. Komponent yo'q qilinganda.

Tartibga e'tibor bering: yangi obuna boshlanishidan oldin eskisi bekor qilindi.

Tozalamaslik - xotira oqishi

Tozalash ixtiyoriy emas. Quyidagilarni ochgan bo'lsangiz, albatta yoping:

OchilganTozalash
setIntervalclearInterval
setTimeoutclearTimeout
addEventListenerremoveEventListener
WebSocket ulanishiclose()
ObunaBekor 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 #

JSX
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"));
Natija
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 #

JSX
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);
Natija
chizishlar soni: 2
holat: yuklandi

Ikki chizish bo'ldi: birinchisi boshlang'ich holat bilan, ikkinchisi effekt holatni o'zgartirgandan keyin.

Obyekt bog'liqlik - yashirin cheksiz sikl

Bog'liqliklar Object.is bilan solishtiriladi, ya'ni obyektlar havola bo'yicha.

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

  1. Bog'liqlikka oddiy qiymat bering: [sozlama.sahifa].
  2. Obyektni komponentdan tashqarida e'lon qiling.
  3. useMemo bilan eslab qoling (17-bo'lim).

Xuddi shu muammo funksiyalarda ham bor - ular ham har chizishda yangi yaratiladi.

Effekt kerak bo'lmagan holatlar #

JSX
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"));
Natija
effekt bilan: Malika Karimova
to'g'ridan-to'g'ri: Malika Karimova

Natija bir xil, lekin Yomon ikki marta chizildi va ortiqcha holat saqladi.

useEffect ni qachon ishlatmaslik kerak

Bu eng ko'p uchraydigan ortiqcha ishlatish:

VazifaTo'g'ri yo'l
Props dan qiymat hisoblashChizish paytida hisoblang
Hodisaga javob berishHodisa ishlovchisida
Holatni props dan olishOdatda umuman kerak emas
Ro'yxatni filtrlashChizish 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 #

JSX
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"));
Natija
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.

Amaliy topshiriq
  1. Effekt chizishdan keyin ishlashini isbotlang.
  2. Uch xil bog'liqliklar ro'yxatini solishtiring.
  3. Massivni unutib, cheksiz sikl yasab ko'ring.
  4. Tozalovchi funksiya qaytaring.
  5. setInterval qo'yib, uni tozalang.
  6. Tozalashni olib tashlab, oqibatini o'ylang.
  7. Obyektni bog'liqlik qilib, muammoni ko'ring.
  8. Uni oddiy qiymatga almashtiring.
  9. Props dan hisoblash uchun effekt yozib, keyin olib tashlang.
  10. eslint-plugin-react-hooks ni o'rnating.

Xulosa #

  • useEffect chizishdan keyin ishlaydi - DOM tayyor bo'ladi.
  • Bog'liqliklar: massivsiz - har chizishda, [] - bir marta, [a] - a o'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.
  • useEffect faqat 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.

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.