5-bo‘lim

Ro'yxatlar va key

map bilan ro'yxat chizish, key nima uchun kerak, indeksni key qilishning oqibati, Fragment uchun key va bo'sh ro'yxat.

🕑 11 daqiqa o‘qish 📄 666 so‘z 👁 0 marta ko‘rilgan
Ushbu bo‘lim mundarijasi
  1. map bilan
  2. key majburiy
  3. Indeksni key qilish - tuzoq
  4. Kalit qayerdan olinadi
  5. Fragment uchun key
  6. Filtrlash va saralash
  7. Bo'sh ro'yxat
  8. Xulosa

React da ro'yxat map bilan chiziladi - maxsus sintaksis yo'q, oddiy JavaScript.

map bilan #

JSX
import { renderToStaticMarkup } from "react-dom/server";
import { chiroyli } from "./dom-muhit.mjs";

function Shaharlar({ royxat }) {
    return (
        <ul>
            {royxat.map((shahar) => (
                <li key={shahar}>{shahar}</li>
            ))}
        </ul>
    );
}

const shaharlar = ["Namangan", "Andijon", "Buxoro"];

console.log(chiroyli(renderToStaticMarkup(<Shaharlar royxat={shaharlar} />)));
Natija
<ul>
<li>Namangan</li>
<li>Andijon</li>
<li>Buxoro</li>
</ul>

map massivni JSX elementlari massiviga aylantiradi. React massivni ko'rsa, hamma elementini ketma-ket chizadi.

key majburiy #

JSX
import { renderToStaticMarkup } from "react-dom/server";
import { chiroyli } from "./dom-muhit.mjs";

const talabalar = [
    { id: 1, ism: "Malika", ball: 88 },
    { id: 2, ism: "Husanboy", ball: 92 },
];

function Jadval() {
    return (
        <table>
            <tbody>
                {talabalar.map((t) => (
                    <tr key={t.id}>
                        <td>{t.ism}</td>
                        <td>{t.ball}</td>
                    </tr>
                ))}
            </tbody>
        </table>
    );
}

console.log(chiroyli(renderToStaticMarkup(<Jadval />)));
Natija
<table>
<tbody>
<tr>
<td>Malika</td>
<td>88</td>
</tr>
<tr>
<td>Husanboy</td>
<td>92</td>
</tr>
</tbody>
</table>

key chiqishda ko'rinmaydi - u React ning ichki ehtiyoji.

key nima uchun kerak

Ro'yxat o'zgarganda React eski va yangi ro'yxatni solishtiradi. Savol shu: qaysi element qaysisiga mos keladi?

key aynan shu savolga javob beradi. U React ga "bu element o'sha eski elementning o'zi" deb aytadi.

key bo'lmasa, React elementlarni o'rni bo'yicha solishtiradi. Oddiy matn uchun bu muammo emas, lekin elementda holat bo'lsa - kiritish maydonidagi matn, fokus, animatsiya - u noto'g'ri elementda qolib ketadi.

Buni quyida haqiqiy misolda ko'ramiz.

key faqat qardoshlar orasida noyob bo'lishi kerak, butun sahifada emas.

Indeksni key qilish - tuzoq #

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

// Yozilgan matn DOM xossasida turadi, atributda emas - shuning
// uchun innerHTML emas, jonli .value o'qiladi.
const qiymatlar = () =>
    [...document.querySelectorAll("input")].map((k) => k.value).join(" | ");

function Royxat({ kalitTuri }) {
    const [qatorlar, ozgartir] = useState([
        { id: "a", nom: "Birinchi" },
        { id: "b", nom: "Ikkinchi" },
    ]);

    return (
        <div>
            <button onClick={() => ozgartir([...qatorlar].reverse())}>
                Teskari
            </button>
            {qatorlar.map((q, i) => (
                <input
                    key={kalitTuri === "indeks" ? i : q.id}
                    defaultValue={q.nom}
                />
            ))}
        </div>
    );
}

// key berildi - shunda ikkinchi tajriba toza holatdan boshlanadi
await chiz(<Royxat key="birinchi" kalitTuri="indeks" />);
await yoz("input", "MEN YOZDIM");
console.log("indeks, teskaridan oldin:", qiymatlar());
await bos("button");
console.log("indeks, teskaridan keyin:", qiymatlar());

await chiz(<Royxat key="ikkinchi" kalitTuri="id" />);
await yoz("input", "MEN YOZDIM");
console.log("id, teskaridan oldin:   ", qiymatlar());
await bos("button");
console.log("id, teskaridan keyin:   ", qiymatlar());
Natija
indeks, teskaridan oldin: MEN YOZDIM | Ikkinchi
indeks, teskaridan keyin: MEN YOZDIM | Ikkinchi
id, teskaridan oldin:    MEN YOZDIM | Ikkinchi
id, teskaridan keyin:    Ikkinchi | MEN YOZDIM

Natijani diqqat bilan o'qing. Ikkala tajriba ham bir xil holatdan boshlandi: birinchi maydonga MEN YOZDIM yozildi.

Keyin "Teskari" bosildi va yo'llar ajraldi:

  • Indeks kalit bilan yozilgan matn birinchi o'rinda qoldi. Lekin u tegishli qator endi ikkinchi o'ringa ko'chgan edi - ya'ni matn noto'g'ri qatorga yopishib qoldi.
  • id kalit bilan matn qator bilan birga ko'chdi va ikkinchi o'ringa o'tdi. Aynan shu kerak edi.
Indeks kalit ma'lumotni noto'g'ri elementga bog'laydi

Indeks - bu o'rin, ma'lumot emas. Ro'yxat o'zgarganda o'rinlar o'zgaradi, lekin key o'zgarmaydi.

React shunda "nol-kalitli element joyida qoldi, faqat uning defaultValue i o'zgardi" deb o'ylaydi. Kiritish maydonining ichidagi matn esa DOM da qolib ketadi - chunki element almashtirilmadi.

Natijada foydalanuvchi yozgan matn butunlay boshqa qatorga tegishli bo'lib qoladi. Bu jimgina sodir bo'ladi va topish juda qiyin.

Indeksni key qilish faqat quyidagi hamma shart bajarilganda xavfsiz:

  1. Ro'yxat hech qachon tartibini o'zgartirmaydi;
  2. Element qo'shilmaydi va o'chirilmaydi;
  3. Elementlarda holat yo'q.

Amalda bu shartlar kamdan-kam bajariladi. Ma'lumotda id bo'lsa, doim o'shani ishlating.

Kalit qayerdan olinadi #

ManbaBaho
Bazadagi idEng yaxshi
Noyob matn (masalan, slug)Yaxshi
crypto.randomUUID() yaratishdaYaxshi
Massiv indeksiOxirgi chora
Math.random() chizishdaHech qachon
Kalitni chizish paytida yaratmang

Bu xato ba'zan uchraydi:

JSX
{royxat.map((x) => <li key={Math.random()}>{x}</li>)}

Har bir chizishda yangi kalit yaratiladi. React hamma elementni yangi deb biladi va butun ro'yxatni qaytadan yasaydi.

Natija: holat yo'qoladi, fokus uchadi, unumdorlik tushadi. Ya'ni key ning maqsadi butunlay buziladi.

Kalit ma'lumotning o'zidan kelishi kerak. Agar ma'lumotda noyob narsa bo'lmasa, uni yaratish paytida bir marta qo'ying va saqlang.

Fragment uchun key #

JSX
import { renderToStaticMarkup } from "react-dom/server";
import { Fragment } from "react";
import { chiroyli } from "./dom-muhit.mjs";

const boblar = [
    { id: 1, sarlavha: "Kirish", matn: "Birinchi bob" },
    { id: 2, sarlavha: "Asoslar", matn: "Ikkinchi bob" },
];

function Hujjat() {
    return (
        <article>
            {boblar.map((b) => (
                <Fragment key={b.id}>
                    <h3>{b.sarlavha}</h3>
                    <p>{b.matn}</p>
                </Fragment>
            ))}
        </article>
    );
}

console.log(chiroyli(renderToStaticMarkup(<Hujjat />)));
Natija
<article>
<h3>Kirish</h3>
<p>Birinchi bob</p>
<h3>Asoslar</h3>
<p>Ikkinchi bob</p>
</article>

Har bir element uchun ikkita teg kerak bo'lsa, ularni o'rash lozim - lekin ortiqcha <div> qo'shmasdan.

Bu yerda qisqa <>...</> shakli ishlamaydi, chunki unga key berib bo'lmaydi. To'liq <Fragment key={...}> yoziladi.

Filtrlash va saralash #

JSX
import { renderToStaticMarkup } from "react-dom/server";
import { chiroyli } from "./dom-muhit.mjs";

const talabalar = [
    { id: 1, ism: "Malika", ball: 88 },
    { id: 2, ism: "Kamola", ball: 54 },
    { id: 3, ism: "Husanboy", ball: 92 },
];

function Otganlar() {
    const korinadigan = talabalar
        .filter((t) => t.ball >= 60)
        .sort((a, b) => b.ball - a.ball);

    return (
        <ol>
            {korinadigan.map((t) => (
                <li key={t.id}>{t.ism}: {t.ball}</li>
            ))}
        </ol>
    );
}

console.log(chiroyli(renderToStaticMarkup(<Otganlar />)));
Natija
<ol>
<li>Husanboy: 92</li>
<li>Malika: 88</li>
</ol>

Filtrlash va saralash - oddiy JavaScript. React ularga hech qanday aloqasi yo'q.

sort asl massivni o'zgartiradi

sort joyida ishlaydi - ya'ni asl massivni o'zgartiradi.

Yuqoridagi kodda muammo yo'q, chunki filter allaqachon yangi massiv yaratgan. Lekin to'g'ridan-to'g'ri saralasangiz:

JSX
talabalar.sort((a, b) => b.ball - a.ball)   // asl massiv buzildi

Bu props yoki holatni o'zgartirish bilan barobar - 4-bo'limdagi qoida buziladi.

Xavfsiz shakllar:

JSX
[...talabalar].sort(...)
talabalar.toSorted(...)

toSorted - yangi massiv qaytaradigan zamonaviy shakl.

Bo'sh ro'yxat #

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

function Royxat({ elementlar }) {
    if (elementlar.length === 0) {
        return <p>Hozircha hech narsa yo'q</p>;
    }

    return (
        <ul>
            {elementlar.map((e) => <li key={e}>{e}</li>)}
        </ul>
    );
}

console.log(renderToStaticMarkup(<Royxat elementlar={[]} />));
console.log(renderToStaticMarkup(<Royxat elementlar={["Bitta"]} />));
Natija
<p>Hozircha hech narsa yo&#x27;q</p>
<ul><li>Bitta</li></ul>

Bo'sh ro'yxat uchun tushunarli xabar chiqaring. Bo'sh <ul> foydalanuvchiga hech narsa aytmaydi va u "yuklanmadimi yoki haqiqatan bo'shmi?" deb o'ylaydi.

Amaliy topshiriq
  1. map bilan ro'yxat chizing.
  2. key ni olib tashlab, konsoldagi ogohlantirishni ko'ring.
  3. Indeksni key qilib, teskari qilish misolini takrorlang.
  4. Xuddi shuni id bilan qayta sinang.
  5. Math.random() ni key qilib, oqibatini kuzating.
  6. Fragment key bilan ikki tegli element chizing.
  7. filter bilan faqat o'tganlarni ko'rsating.
  8. toSorted bilan xavfsiz saralang.
  9. sort ni to'g'ridan-to'g'ri ishlatib, asl massiv o'zgarishini ko'ring.
  10. Bo'sh ro'yxat uchun xabar qo'shing.

Xulosa #

  • Ro'yxat map bilan chiziladi - maxsus sintaksis yo'q.
  • key React ga qaysi element qaysisi ekanini aytadi; u chiqishda ko'rinmaydi.
  • Indeksni key qilish holatni noto'g'ri elementga bog'laydi - buni misolda ko'rdik.
  • Kalit ma'lumotning o'zidan kelsin; chizish paytida yaratmang.
  • Ikki tegli element uchun <Fragment key={...}>; qisqa shaklga key berib bo'lmaydi.
  • sort asl massivni o'zgartiradi - [...massiv].sort() yoki toSorted.
  • Bo'sh ro'yxat uchun tushunarli xabar chiqaring.

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