11-bo‘lim

Ma'lumot olish

useEffect bilan so'rov yuborish, yuklanish va xato holatlari, poyga holati va uni AbortController bilan hal qilish.

🕑 9 daqiqa o‘qish 📄 535 so‘z 👁 0 marta ko‘rilgan
Ushbu bo‘lim mundarijasi
  1. Uchta holat
  2. Xatoni qayta ishlash
  3. Poyga holati
  4. Tuzatilgan shakl
  5. AbortController
  6. Xulosa

Ilova ma'lumotni serverdan oladi. Node.js darsligida server tomonini yozgan edik - endi mijoz tomonini ko'ramiz.

Uchta holat #

Har qanday so'rovda uch holat bo'ladi: yuklanmoqda, xato, tayyor.

JSX
import { useState, useEffect } from "react";
import { createServer } from "node:http";
import { chiz, kut, matn } from "./dom-muhit.mjs";

const server = createServer((sorov, javob) => {
    javob.writeHead(200, { "Content-Type": "application/json" });
    javob.end(JSON.stringify({ ism: "Malika", ball: 88 }));
});
server.listen(0);
const asos = `http://localhost:${server.address().port}`;

function Profil({ manzil }) {
    const [malumot, malumotniOzgartir] = useState(null);
    const [yuklanmoqda, yuklanishniOzgartir] = useState(true);
    const [xato, xatoniOzgartir] = useState(null);

    useEffect(() => {
        let bekor = false;

        async function ol() {
            yuklanishniOzgartir(true);
            xatoniOzgartir(null);
            try {
                const javob = await fetch(manzil);
                if (!javob.ok) throw new Error(`holat ${javob.status}`);
                const natija = await javob.json();
                if (!bekor) malumotniOzgartir(natija);
            } catch (x) {
                if (!bekor) xatoniOzgartir(x.message);
            } finally {
                if (!bekor) yuklanishniOzgartir(false);
            }
        }

        ol();
        return () => { bekor = true; };
    }, [manzil]);

    if (yuklanmoqda) return <p id="holat">Yuklanmoqda...</p>;
    if (xato) return <p id="holat">Xato: {xato}</p>;
    return <p id="holat">{malumot.ism}: {malumot.ball}</p>;
}

await chiz(<Profil manzil={asos} />);
console.log("boshida:", matn("#holat"));

await kut();
console.log("javobdan keyin:", matn("#holat"));

server.close();
Natija
boshida: Yuklanmoqda...
javobdan keyin: Malika: 88

Uch holat uchun uchta alohida useState. Bu eng oddiy va eng tushunarli shakl.

Yuklanish holatini unutmang

Ko'p qo'llanmada faqat ma'lumot saqlanadi:

JSX
const [malumot, ozgartir] = useState(null);

Muammo: null ikki xil ma'noni bildiradi - "hali yuklanmadi" va "topilmadi". Foydalanuvchi bo'sh ekranni ko'radi va nima bo'layotganini bilmaydi.

Uchala holatni ham ochiq saqlang. Aks holda interfeys "sinmagan, lekin tushunarsiz" bo'lib qoladi.

Xatoni qayta ishlash #

JSX
import { useState, useEffect } from "react";
import { createServer } from "node:http";
import { chiz, kut, matn } from "./dom-muhit.mjs";

const server = createServer((sorov, javob) => {
    if (sorov.url === "/yoq") {
        javob.writeHead(404, { "Content-Type": "application/json" });
        javob.end(JSON.stringify({ xato: "topilmadi" }));
        return;
    }
    javob.writeHead(200, { "Content-Type": "application/json" });
    javob.end(JSON.stringify({ holat: "yaxshi" }));
});
server.listen(0);
const asos = `http://localhost:${server.address().port}`;

function Yuklovchi({ manzil }) {
    const [holat, ozgartir] = useState("yuklanmoqda");

    useEffect(() => {
        let bekor = false;
        fetch(manzil)
            .then((j) => {
                if (!j.ok) throw new Error(`server ${j.status} qaytardi`);
                return j.json();
            })
            .then((m) => { if (!bekor) ozgartir(`tayyor: ${m.holat}`); })
            .catch((x) => { if (!bekor) ozgartir(`xato: ${x.message}`); });
        return () => { bekor = true; };
    }, [manzil]);

    return <p id="holat">{holat}</p>;
}

await chiz(<Yuklovchi manzil={`${asos}/bor`} />);
await kut();
console.log("mavjud yo'l:", matn("#holat"));

await chiz(<Yuklovchi key="2" manzil={`${asos}/yoq`} />);
await kut();
console.log("yo'q yo'l:", matn("#holat"));

server.close();
Natija
mavjud yo'l: tayyor: yaxshi
yo'q yo'l: xato: server 404 qaytardi
fetch xato holatlarda rad etmaydi

Bu juda ko'p xatoga sabab bo'ladi: fetch faqat tarmoq uzilganda rad etadi.

Server 404 yoki 500 qaytarsa, fetch uni muvaffaqiyat deb biladi va .catch ishlamaydi.

Shuning uchun javob.ok ni qo'lda tekshirish kerak:

JavaScript
if (!javob.ok) throw new Error(`holat ${javob.status}`);

ok - holat kodi 200 va 299 orasida bo'lsa true.

Buni unutsangiz, 404 sahifasining HTML ini JSON deb o'qishga urinasiz va chalkash xato olasiz.

Poyga holati #

JSX
import { useState, useEffect } from "react";
import { chiz, kut } from "./dom-muhit.mjs";

const izlar = [];

function sekinSorov(nom, kechikish) {
    return new Promise((yechim) => setTimeout(() => yechim(nom), kechikish));
}

function Yomon({ so }) {
    const [natija, ozgartir] = useState("");

    useEffect(() => {
        const kechikish = so === "birinchi" ? 80 : 10;
        sekinSorov(so, kechikish).then((n) => {
            izlar.push(`yozildi: ${n}`);
            ozgartir(n);
        });
    }, [so]);

    return <p id="natija">{natija}</p>;
}

await chiz(<Yomon so="birinchi" />);
await chiz(<Yomon so="ikkinchi" />);

await kut(150);
console.log(izlar.join("\n"));
console.log("ekranda:", document.querySelector("#natija").textContent);
Natija
yozildi: ikkinchi
yozildi: birinchi
ekranda: birinchi

Ekranda birinchi qoldi - garchi foydalanuvchi oxirgi marta ikkinchi ni so'ragan bo'lsa ham.

Poyga holati - eski javob keyin kelib qoladi

Sodir bo'lgan narsa:

  1. birinchi so'raldi - u sekin (80 ms);
  2. ikkinchi so'raldi - u tez (10 ms) va birinchi bo'lib keldi;
  3. Keyin birinchi ning javobi kelib, natijani ustiga yozdi.

Natijada foydalanuvchi eskirgan ma'lumotni ko'radi. Haqiqiy qidiruv maydonida bu doim sodir bo'ladi: har harfda yangi so'rov ketadi va ular turli tezlikda qaytadi.

Yechim - yuqoridagi misollarda ishlatilgan bekor bayrog'i: tozalovchi funksiya uni true qiladi va eskirgan javob holatni o'zgartirmaydi.

Keyingi bo'limda buni AbortController bilan ham ko'ramiz - u so'rovning o'zini to'xtatadi.

Tuzatilgan shakl #

JSX
import { useState, useEffect } from "react";
import { chiz, kut } from "./dom-muhit.mjs";

function sekinSorov(nom, kechikish) {
    return new Promise((yechim) => setTimeout(() => yechim(nom), kechikish));
}

function Yaxshi({ so }) {
    const [natija, ozgartir] = useState("");

    useEffect(() => {
        let bekor = false;
        const kechikish = so === "birinchi" ? 80 : 10;

        sekinSorov(so, kechikish).then((n) => {
            if (!bekor) ozgartir(n);
        });

        return () => { bekor = true; };
    }, [so]);

    return <p id="natija">{natija}</p>;
}

await chiz(<Yaxshi so="birinchi" />);
await chiz(<Yaxshi so="ikkinchi" />);

await kut(150);
console.log("ekranda:", document.querySelector("#natija").textContent);
Natija
ekranda: ikkinchi

Endi ekranda oxirgi so'ralgan qiymat turibdi.

bekor bayrog'i tozalovchi funksiyada true bo'ladi, shuning uchun eskirgan javob e'tiborsiz qoladi.

AbortController #

JSX
import { useState, useEffect } from "react";
import { createServer } from "node:http";
import { chiz, kut, matn } from "./dom-muhit.mjs";

const server = createServer((sorov, javob) => {
    setTimeout(() => {
        javob.writeHead(200, { "Content-Type": "application/json" });
        javob.end(JSON.stringify({ natija: sorov.url.slice(1) }));
    }, 30);
});
server.listen(0);
const asos = `http://localhost:${server.address().port}`;

function Qidiruv({ so }) {
    const [natija, ozgartir] = useState("kutilmoqda");

    useEffect(() => {
        const boshqaruvchi = new AbortController();

        fetch(`${asos}/${so}`, { signal: boshqaruvchi.signal })
            .then((j) => j.json())
            .then((m) => ozgartir(m.natija))
            .catch((x) => {
                if (x.name !== "AbortError") ozgartir(`xato: ${x.message}`);
            });

        return () => boshqaruvchi.abort();
    }, [so]);

    return <p id="natija">{natija}</p>;
}

await chiz(<Qidiruv so="birinchi" />);
await chiz(<Qidiruv so="ikkinchi" />);

await kut(150);
console.log("ekranda:", matn("#natija"));

server.close();
Natija
ekranda: ikkinchi

AbortController bayroqdan bir qadam ilgari boradi: u so'rovni haqiqatan to'xtatadi, ya'ni tarmoq ham bo'shaydi.

Bekor qilingan so'rov AbortError bilan rad etiladi - uni oddiy xatodan ajratish kerak, chunki bu kutilgan hol.

Amalda kutubxona ishlatiladi

Yuqoridagi kod to'g'ri, lekin uzun. Va u hali keshni, qayta urinishni, sahifalashni qamrab olmadi.

Haqiqiy loyihalarda odatda tayyor yechim olinadi:

VositaIzoh
TanStack QueryEng mashhuri; kesh, qayta urinish, yangilash
SWRYengilroq, soddaroq
Next.js kabi freymvorklarMa'lumot olish ichiga qurilgan

Lekin ular sehr emas: ichkarida aynan shu naqshlar bor. Qo'lda bir marta yozib ko'rgan bo'lsangiz, kutubxona nima qilayotganini tushunasiz va muammo chiqqanda uni tuzata olasiz.

Amaliy topshiriq
  1. Uch holatli ma'lumot oluvchi komponent yozing.
  2. javob.ok ni tekshirmasdan, 404 da nima bo'lishini ko'ring.
  3. Tekshiruvni qo'shib, xatoni to'g'ri ushlang.
  4. Ikki so'rovni turli tezlikda yuborib, poyga holatini yasang.
  5. bekor bayrog'i bilan uni to'g'rilang.
  6. AbortController bilan so'rovni to'xtating.
  7. AbortError ni boshqa xatolardan ajrating.
  8. Bog'liqliklar ro'yxatiga manzilni qo'shing.
  9. Yuklanish holatida xabar ko'rsating.
  10. Xato holatida qayta urinish tugmasini qo'shing.

Xulosa #

  • Har bir so'rovda uch holat: yuklanmoqda, xato, tayyor.
  • fetch 404 va 500 da rad etmaydi - javob.ok ni qo'lda tekshiring.
  • Tez o'zgaradigan so'rovlarda poyga holati paydo bo'ladi: eski javob yangisining ustiga yozadi.
  • Yechim - tozalovchi funksiyadagi bekor bayrog'i yoki AbortController.
  • AbortError - kutilgan hol, uni alohida ajrating.
  • Amalda TanStack Query kabi kutubxona ishlatiladi, lekin ichkarida aynan shu naqshlar.

Keyingi bo'limda useRef ni 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.