13-bo‘lim

Kontekst - useContext

Props burg'ulash muammosi, createContext va Provider, React 19 dagi qisqa shakl, odatiy qiymat va kontekstni qachon ishlatmaslik.

🕑 10 daqiqa o‘qish 📄 560 so‘z 👁 0 marta ko‘rilgan
Ushbu bo‘lim mundarijasi
  1. Muammo: props burg'ulash
  2. Kontekst bilan
  3. O'zgaruvchan kontekst
  4. O'z ilgagingiz bilan o'rash
  5. Kontekst o'zgarganda nima bo'ladi
  6. Qachon kontekst kerak emas
  7. Xulosa

Props ma'lumotni yuqoridan pastga uzatadi. Lekin ma'lumot besh qavat pastga tushishi kerak bo'lsa-chi?

Muammo: props burg'ulash #

JSX
import { renderToStaticMarkup } from "react-dom/server";

function Tugma({ mavzu }) {
    return <button className={mavzu}>Bosish</button>;
}

function Panel({ mavzu }) {
    return <div><Tugma mavzu={mavzu} /></div>;
}

function Yon({ mavzu }) {
    return <aside><Panel mavzu={mavzu} /></aside>;
}

function Ilova() {
    const mavzu = "qorongi";
    return <Yon mavzu={mavzu} />;
}

console.log(renderToStaticMarkup(<Ilova />));
Natija
<aside><div><button class="qorongi">Bosish</button></div></aside>

Yon va Panel ga mavzu umuman kerak emas - ular uni faqat pastga uzatib beradi.

Bu props burg'ulash (prop drilling) deb ataladi. Ikki qavatda u muammo emas, beshta qavatda esa kod shovqinga to'ladi.

Kontekst bilan #

JSX
import { createContext, useContext } from "react";
import { renderToStaticMarkup } from "react-dom/server";

const MavzuKonteksti = createContext("yorug");

function Tugma() {
    const mavzu = useContext(MavzuKonteksti);
    return <button className={mavzu}>Bosish</button>;
}

function Panel() {
    return <div><Tugma /></div>;
}

function Yon() {
    return <aside><Panel /></aside>;
}

function Ilova() {
    return (
        <MavzuKonteksti value="qorongi">
            <Yon />
        </MavzuKonteksti>
    );
}

console.log(renderToStaticMarkup(<Ilova />));
console.log(renderToStaticMarkup(<Tugma />));
Natija
<aside><div><button class="qorongi">Bosish</button></div></aside>
<button class="yorug">Bosish</button>

Yon va Panel endi mavzu haqida hech narsa bilmaydi.

Ikkinchi qator muhim: Tugma kontekstdan tashqarida ishlatilganda, createContext ga berilgan odatiy qiymat ("yorug") ishlatildi.

React 19: Provider so'zi kerak emas

React 18 va undan oldin shunday yozilardi:

JSX
<MavzuKonteksti.Provider value="qorongi">
    <Yon />
</MavzuKonteksti.Provider>

React 19 da kontekstning o'zini komponent sifatida ishlatish mumkin:

JSX
<MavzuKonteksti value="qorongi">

Eski shakl hali ishlaydi, lekin yangisi qisqaroq. Internetdagi qo'llanmalarning ko'pchiligi hali .Provider bilan yozilgan.

O'zgaruvchan kontekst #

JSX
import { createContext, useContext, useState } from "react";
import { chiz, bos, matn } from "./dom-muhit.mjs";

const MavzuKonteksti = createContext(null);

function Almashtirgich() {
    const { mavzu, almashtir } = useContext(MavzuKonteksti);
    return (
        <button onClick={almashtir}>
            Hozir: {mavzu}
        </button>
    );
}

function Korinish() {
    const { mavzu } = useContext(MavzuKonteksti);
    return <p id="korinish">Ko'rinish: {mavzu}</p>;
}

function Ilova() {
    const [mavzu, ozgartir] = useState("yorug");

    const qiymat = {
        mavzu,
        almashtir: () =>
            ozgartir((o) => (o === "yorug" ? "qorongi" : "yorug")),
    };

    return (
        <MavzuKonteksti value={qiymat}>
            <Almashtirgich />
            <Korinish />
        </MavzuKonteksti>
    );
}

await chiz(<Ilova />);
console.log(matn("button"), "|", matn("#korinish"));

await bos("button");
console.log(matn("button"), "|", matn("#korinish"));
Natija
Hozir: yorug | Ko'rinish: yorug
Hozir: qorongi | Ko'rinish: qorongi

Kontekstga obyekt berildi: qiymat va uni o'zgartiradigan funksiya.

Ikkala komponent ham bir vaqtda yangilandi - ular bir manbadan o'qiyapti.

O'z ilgagingiz bilan o'rash #

JSX
import { createContext, useContext, useState } from "react";

const MavzuKonteksti = createContext(null);

export function MavzuTaminlovchi({ children, boshlangich = "yorug" }) {
    const [mavzu, ozgartir] = useState(boshlangich);

    const qiymat = {
        mavzu,
        almashtir: () =>
            ozgartir((o) => (o === "yorug" ? "qorongi" : "yorug")),
    };

    return <MavzuKonteksti value={qiymat}>{children}</MavzuKonteksti>;
}

export function useMavzu() {
    const qiymat = useContext(MavzuKonteksti);
    if (qiymat === null) {
        throw new Error("useMavzu faqat MavzuTaminlovchi ichida ishlaydi");
    }
    return qiymat;
}
JSX
import { MavzuTaminlovchi, useMavzu } from "./mavzu-konteksti.mjs";
import { chiz, bos, matn } from "./dom-muhit.mjs";

function Tugma() {
    const { mavzu, almashtir } = useMavzu();
    return <button onClick={almashtir}>{mavzu}</button>;
}

function Xato() {
    try {
        useMavzu();
        return <p id="xato">ishladi</p>;
    } catch (x) {
        return <p id="xato">{x.message}</p>;
    }
}

await chiz(
    <MavzuTaminlovchi boshlangich="qorongi">
        <Tugma />
    </MavzuTaminlovchi>,
);
console.log(matn("button"));

await bos("button");
console.log(matn("button"));

await chiz(<Xato />);
console.log(matn("#xato"));
Natija
qorongi
yorug
useMavzu faqat MavzuTaminlovchi ichida ishlaydi

Bu standart naqsh: kontekstning o'zini eksport qilmasdan, ikkita narsani berish:

  1. Ta'minlovchi komponent;
  2. O'z ilgagingiz - useMavzu.
Nima uchun tekshiruv qo'shiladi

useMavzu ichidagi throw bejiz emas.

Tekshiruvsiz, kontekstdan tashqarida chaqirilganda null qaytardi va xato ancha keyin - qiymat.mavzu o'qilganda - chiqardi:

Natija
Cannot read properties of null (reading 'mavzu')

Bu xabar muammoning sababini aytmaydi. Yuqoridagi shakl esa aniq aytadi: ta'minlovchi unutilgan.

Xatoni imkon qadar erta va tushunarli qilish - yaxshi kutubxona yozishning asosiy qoidalaridan biri.

Kontekst o'zgarganda nima bo'ladi #

JSX
import { createContext, useContext, useState } from "react";
import { chiz, bos } from "./dom-muhit.mjs";

const Kontekst = createContext(null);

const izlar = [];

function Oquvchi() {
    const qiymat = useContext(Kontekst);
    izlar.push(`Oquvchi chizildi: ${qiymat}`);
    return <p>{qiymat}</p>;
}

function Begona() {
    izlar.push("Begona chizildi");
    return <span>begona</span>;
}

function Ilova() {
    const [son, ozgartir] = useState(1);

    return (
        <Kontekst value={son}>
            <button onClick={() => ozgartir(son + 1)}>Oshirish</button>
            <Oquvchi />
            <Begona />
        </Kontekst>
    );
}

await chiz(<Ilova />);
izlar.push("--- bosildi ---");
await bos("button");

console.log(izlar.join("\n"));
Natija
Oquvchi chizildi: 1
Begona chizildi
--- bosildi ---
Oquvchi chizildi: 2
Begona chizildi

Begona kontekstni o'qimaydi, lekin u ham qayta chizildi.

Kontekst unumdorlik vositasi emas

Ko'p odam kontekstni "qayta chizishni kamaytirish" uchun deb o'ylaydi. Aslida teskarisi.

Yuqorida Begona kontekstga umuman tegmaydi, lekin baribir qayta chizildi - chunki uning otasi qayta chizildi. Kontekst buni o'zgartirmaydi.

Kontekst faqat props uzatishni soddalashtiradi, chizishlarni emas.

Agar kontekst qiymati tez-tez o'zgarsa va daraxt katta bo'lsa, bu sezilarli sekinlik keltirishi mumkin. Yechimlar:

  1. Kontekstni bo'lish - o'zgarmaydigan qismini alohida kontekstga ajratish;
  2. children orqali uzatish (16-bo'lim);
  3. memo bilan qismlarni ajratish (17-bo'lim).

Qachon kontekst kerak emas #

HolatYechim
Ikki qavat pastga uzatishOddiy props
Bitta komponentga tegishli holatuseState
Butun ilovaga kerak (mavzu, til, foydalanuvchi)Kontekst
Murakkab, tez o'zgaradigan holatMaxsus kutubxona
Hamma narsani kontekstga solmang

Kontekst qulay ko'rinadi va uni haddan ortiq ishlatish oson.

Muammolari:

  1. Komponent qayerdan ma'lumot olayotgani ko'rinmaydi - props kabi ochiq emas.
  2. Komponentni alohida sinash qiyinlashadi: test uchun ham ta'minlovchi kerak bo'ladi.
  3. Qayta ishlatish qiyinlashadi: komponent endi ma'lum bir kontekstga bog'lanib qoladi.

Amaliy qoida: kontekst - butun ilovaga tegishli, kam o'zgaradigan narsalar uchun: mavzu, til, kirgan foydalanuvchi, marshrutlash.

Ikki-uch qavatli uzatish uchun oddiy props yaxshiroq: u ochiq va kuzatish oson.

Amaliy topshiriq
  1. To'rt qavatli props burg'ulash yasang.
  2. Uni kontekst bilan almashtiring.
  3. createContext ga odatiy qiymat berib, ta'minlovchisiz sinang.
  4. Kontekstga obyekt berib, funksiyani ham uzating.
  5. React 19 ning qisqa shaklini ishlating.
  6. Eski .Provider shaklini ham yozib ko'ring.
  7. O'z ilgagingiz bilan kontekstni o'rang.
  8. Ta'minlovchisiz chaqirganda tushunarli xato bering.
  9. Kontekst o'zgarganda qaysi komponentlar chizilishini kuzating.
  10. Ikki qavatli uzatishni props bilan qoldiring.

Xulosa #

  • Kontekst props burg'ulash muammosini hal qiladi.
  • createContext(odatiy) yaratadi, useContext o'qiydi.
  • React 19 da <Kontekst value={...}> - .Provider kerak emas.
  • Odatiy qiymat faqat ta'minlovchisiz ishlatilganda amal qiladi.
  • Standart naqsh: ta'minlovchi + o'z ilgagingiz, tekshiruv bilan.
  • Kontekst unumdorlik vositasi emas - u qayta chizishni kamaytirmaydi.
  • Kontekst kam o'zgaradigan, butun ilovaga tegishli narsalar uchun.

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