React.memo — component ni keshlash, qachon kerak
Muammodan boshlaylik
Mahsulotlar sahifasi: tepada qidiruv maydoni, pastda 500 ta mahsulot kartochkasi.
function Katalog({ mahsulotlar }) {
const [qidiruv, setQidiruv] = useState('');
return (
<>
<input value={qidiruv} onChange={(e) => setQidiruv(e.target.value)} />
<MahsulotRoyxati mahsulotlar={mahsulotlar} />
</>
);
}
Har bir harf yozilganda Katalog render bo'ladi → MahsulotRoyxati va uning 500 ta kartochkasi ham (67-dars). Telefonda yozish sezilarli sekinlashdi: harflar kechikib paydo bo'lyapti.
mahsulotlar o'zgarmagan — ro'yxatni qayta render qilishning ma'nosi yo'q. React ga buni aytish kerak.
React.memo
import { memo } from 'react';
const MahsulotRoyxati = memo(function MahsulotRoyxati({ mahsulotlar }) {
return (
<ul>
{mahsulotlar.map((m) => <MahsulotKartochka key={m.id} mahsulot={m} />)}
</ul>
);
});
memo komponentni o'raydi va React ga aytadi: "ota-ona render bo'lganda, avval props larni solishtir. Hammasi oldingisi bilan bir xil bo'lsa — meni render qilma, oldingi natijani ishlat."
Endi qidiruvda yozilganda MahsulotRoyxati render bo'lmaydi — mahsulotlar o'sha massiv.
Qanday solishtiradi
Har bir prop Object.is bilan (deyarli ===) — sayoz (shallow) solishtiriladi:
Object.is(5, 5) // true
Object.is('a', 'a') // true
Object.is([1, 2], [1, 2]) // false — har xil massivlar
Object.is({ a: 1 }, { a: 1 }) // false — har xil obyektlar
Object.is(() => {}, () => {}) // false — har xil funksiyalar
Oddiy qiymatlar (son, string, boolean) qiymat bo'yicha; obyekt, massiv va funksiyalar — havola bo'yicha.
memo ni buzadigan narsalar
Bu — memo ishlatishdagi eng katta tuzoq:
function Katalog({ mahsulotlar }) {
const [qidiruv, setQidiruv] = useState('');
return (
<MahsulotRoyxati
mahsulotlar={mahsulotlar}
filtr={{ kategoriya: 'kitob' }} // ❌ har renderda yangi obyekt
onTanlash={(id) => console.log(id)} // ❌ har renderda yangi funksiya
ustunlar={['nomi', 'narx']} // ❌ har renderda yangi massiv
/>
);
}
Har renderda yangi obyekt, funksiya va massiv → Object.is → false → memo har safar "props o'zgardi" deydi → har safar render. memo foydasiz bo'ldi, va qo'shimcha solishtirish xarajati qo'shildi.
Yechimlar
// 1. O'zgarmas qiymatlarni komponentdan tashqariga
const FILTR = { kategoriya: 'kitob' };
const USTUNLAR = ['nomi', 'narx'];
function Katalog({ mahsulotlar }) {
const [qidiruv, setQidiruv] = useState('');
// 2. Funksiyalar — useCallback (16-dars)
const onTanlash = useCallback((id) => {
console.log(id);
}, []);
// 3. Hisoblangan obyektlar — useMemo (15-dars)
const saralangan = useMemo(
() => [...mahsulotlar].sort((a, b) => a.narx - b.narx),
[mahsulotlar]
);
return (
<MahsulotRoyxati
mahsulotlar={saralangan}
filtr={FILTR}
ustunlar={USTUNLAR}
onTanlash={onTanlash}
/>
);
}
memo, useMemo va useCallback — birgalikda ishlaydigan vositalar. useCallback ning asosiy vazifasi — aynan memo qilingan bolaga barqaror funksiya berish.
children ham prop
<MemoKomponent>
<p>Matn</p> {/* har renderda yangi JSX obyekti → memo ishlamaydi */}
</MemoKomponent>
JSX — har renderda yangi obyekt. children qabul qiladigan komponentga memo deyarli foyda bermaydi.
Kartochkalar darajasida
Ro'yxat o'zgaradigan bo'lsa (masalan, filtrlash natijasida), har bir kartochkani memo qilish foydali:
const MahsulotKartochka = memo(function MahsulotKartochka({ mahsulot, onSavatga }) {
return (
<article>
<h3>{mahsulot.nomi}</h3>
<p>{mahsulot.narx.toLocaleString()} so'm</p>
<button onClick={() => onSavatga(mahsulot.id)}>Savatga</button>
</article>
);
});
Bitta mahsulot "Savatga" qo'shilib, uning obyekti yangilansa — faqat o'sha kartochka render bo'ladi, qolgan 499 tasi emas. Buning uchun onSavatga useCallback bilan, va mahsulot obyektlari o'zgarmas tarzda yangilanishi kerak (o'zgarmagan mahsulotlar — o'sha obyektlar).
O'z solishtirish funksiyangiz
const Grafik = memo(
function Grafik({ malumot, sarlavha }) { /* ... */ },
(oldingi, keyingi) =>
oldingi.malumot.length === keyingi.malumot.length &&
oldingi.sarlavha === keyingi.sarlavha
);
Ikkinchi argument — true qaytarsa render qilinmaydi. Juda kamdan-kam kerak va xavfli: biror prop ni solishtirishni unutsangiz, komponent eskirgan ma'lumotni ko'rsatadi. Chuqur solishtirish (JSON.stringify, isEqual) esa ko'pincha render dan ham qimmatroq.
Qachon memo kerak
memo — bepul emas: har renderda props larni solishtirish va eski props larni xotirada saqlash.
✅ Foydali:
- Komponent tez-tez bir xil props bilan render bo'ladi
- Uning render i sezilarli qimmat (katta ro'yxat, grafik, murakkab hisoblash)
- Props lar oddiy qiymatlar yoki barqaror havolalar (yoki ularni barqaror qilish oson)
❌ Foydasiz yoki zararli:
- Kichik, arzon komponentlar — tugma, ikonka, matn
- Props deyarli har doim o'zgaradi
- Props ga har renderda yangi obyekt/funksiya beriladi va siz buni tuzatmaysiz
childrenqabul qiladi
[!TIP] Tartib: avval o'lchang (71-dars, React Profiler), keyin tuzilmani yaxshilang (67-dars: state ni pastga tushirish,
children), va faqat shundan keyinmemo. "Har ehtimolga qarshi" hamma joygamemoqo'yish kodni murakkablashtiradi va ko'pincha hech narsa bermaydi. Agar loyihada React Compiler yoqilgan bo'lsa, u bularning ko'pini avtomatik qiladi.
Muammoga qaytib — yanada yaxshi yechim
Darsning boshidagi qidiruv uchun memo yagona yechim emas:
function Katalog({ mahsulotlar }) {
return (
<>
<Qidiruv /> {/* state shu yerda */}
<MahsulotRoyxati mahsulotlar={mahsulotlar} /> {/* ta'sirlanmaydi */}
</>
);
}
Agar qidiruv ro'yxatni filtrlashi kerak bo'lsa (ya'ni ro'yxat qidiruvga bog'liq bo'lsa), memo yordam bermaydi — ro'yxat haqiqatan o'zgaryapti. U holda useDeferredValue (82-dars) yoki virtualizatsiya (70-dars) kerak.
Nima uchun shunday?
Nima uchun memo faqat sayoz solishtiradi — chuqur solishtirish ishonchliroq emasmi?
Chuqur solishtirish ishonchliroq, lekin oldindan aytib bo'lmaydigan darajada qimmat. 10 000 elementli massivni har renderda element-ma-element tekshirish komponentni render qilishdan ham sekinroq bo'lishi mumkin — optimizatsiya teskari natija beradi. Sayoz solishtirish esa doim tez: har bir prop uchun bitta ===. Bu yondashuv React ning boshqa qoidasi bilan uyg'unlashadi: ma'lumotlar o'zgarmas tarzda yangilanadi (9-dars). Agar massiv o'zgargan bo'lsa — u yangi massiv; o'zgarmagan bo'lsa — o'sha massiv. Shu kelishuv bajarilsa, havolani solishtirish mazmunni solishtirish bilan bir xil natija beradi — lekin bir zumda.
Xulosa
Eslab qoling:
memo(Komponent)— props o'zgarmasa, ota-ona render bo'lganda ham render qilmaydi- Solishtirish — sayoz (
Object.is): obyekt, massiv, funksiya — havola bo'yicha - Har renderda yangi
{},[],() => {}—memoni buzadi - Yechimlar: konstantalarni tashqariga,
useCallback(funksiyalar),useMemo(hisoblangan qiymatlar) childrenli komponentlargamemodeyarli foydasiz- O'z solishtirish funksiyasi — kamdan-kam va ehtiyotkorlik bilan
- Avval o'lchang, keyin tuzilmani yaxshilang, oxirida
memo
Keyingi dars
69-dars: Code Splitting — dynamic import, lazy, Suspense