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.
Ushbu bo‘lim mundarijasi
React da ro'yxat map bilan chiziladi - maxsus sintaksis yo'q,
oddiy JavaScript.
map bilan #
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} />)));
<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 #
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 />)));
<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.
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 #
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());
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.
idkalit bilan matn qator bilan birga ko'chdi va ikkinchi o'ringa o'tdi. Aynan shu kerak edi.
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:
- Ro'yxat hech qachon tartibini o'zgartirmaydi;
- Element qo'shilmaydi va o'chirilmaydi;
- Elementlarda holat yo'q.
Amalda bu shartlar kamdan-kam bajariladi. Ma'lumotda id bo'lsa,
doim o'shani ishlating.
Kalit qayerdan olinadi #
| Manba | Baho |
|---|---|
Bazadagi id | Eng yaxshi |
| Noyob matn (masalan, slug) | Yaxshi |
crypto.randomUUID() yaratishda | Yaxshi |
| Massiv indeksi | Oxirgi chora |
Math.random() chizishda | Hech qachon |
Bu xato ba'zan uchraydi:
{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 #
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 />)));
<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 #
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 />)));
<ol>
<li>Husanboy: 92</li>
<li>Malika: 88</li>
</ol>
Filtrlash va saralash - oddiy JavaScript. React ularga hech qanday aloqasi yo'q.
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:
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:
[...talabalar].sort(...)
talabalar.toSorted(...)
toSorted - yangi massiv qaytaradigan zamonaviy shakl.
Bo'sh ro'yxat #
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"]} />));
<p>Hozircha hech narsa yo'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.
mapbilan ro'yxat chizing.keyni olib tashlab, konsoldagi ogohlantirishni ko'ring.- Indeksni
keyqilib, teskari qilish misolini takrorlang. - Xuddi shuni
idbilan qayta sinang. Math.random()nikeyqilib, oqibatini kuzating.Fragment keybilan ikki tegli element chizing.filterbilan faqat o'tganlarni ko'rsating.toSortedbilan xavfsiz saralang.sortni to'g'ridan-to'g'ri ishlatib, asl massiv o'zgarishini ko'ring.- Bo'sh ro'yxat uchun xabar qo'shing.
Xulosa #
- Ro'yxat
mapbilan chiziladi - maxsus sintaksis yo'q. keyReact ga qaysi element qaysisi ekanini aytadi; u chiqishda ko'rinmaydi.- Indeksni
keyqilish 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 shaklgakeyberib bo'lmaydi. sortasl massivni o'zgartiradi -[...massiv].sort()yokitoSorted.- Bo'sh ro'yxat uchun tushunarli xabar chiqaring.
Keyingi bo'limda hodisalarni 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.