Concurrent Features — useTransition, useDeferredValue
Muammodan boshlaylik
5000 ta mahsulotli katalog va qidiruv maydoni. Har harf yozilganda ro'yxat filtrlanadi:
function Katalog({ mahsulotlar }) {
const [qidiruv, setQidiruv] = useState('');
const natija = mahsulotlar.filter((m) =>
m.nomi.toLowerCase().includes(qidiruv.toLowerCase())
);
return (
<>
<input value={qidiruv} onChange={(e) => setQidiruv(e.target.value)} />
<MahsulotRoyxati mahsulotlar={natija} /> {/* og'ir render — 200 ms */}
</>
);
}
Foydalanuvchi "noutbuk" deb yozadi. Har bir harfdan keyin React ro'yxatni render qiladi — 200 ms. Shu vaqtda input ham qotadi: harflar kechikib, bo'laklab paydo bo'ladi. Yozish yoqimsiz.
Bu yerda ikki xil yangilanish bor:
- Input qiymati — shoshilinch: foydalanuvchi bosgan tugma darhol ko'rinishi kerak
- Ro'yxat — shoshilinch emas: 100–200 ms kechiksa ham hech kim sezmaydi
React 18 dan oldin barcha yangilanishlar teng edi: React render ni boshlasa, oxirigacha to'xtamasdan bajarardi. Concurrent rendering — React ga yangilanishlarning ustuvorligi ni aytish imkoniyati.
Concurrent rendering nima
Concurrent (parallel) rendering — React render ni to'xtatib turishi, muhimroq ishni bajarishi va keyin qaytishi mumkin:
Oddiy: [──── ro'yxat render (200ms) ────][input] ← input kutadi
Concurrent: [ro'yx][input][ro'yxat davomi...][input][ro'yxat...]
↑ to'xtatildi, input birinchi
Shoshilinch bo'lmagan render fonda bajariladi va foydalanuvchi har yangi harf yozganda to'xtatiladi. Eskirgan render (eski qidiruv so'zi uchun) tashlab yuboriladi — uni tugatishning ma'nosi yo'q.
Siz React ga qaysi yangilanish shoshilinch emasligini ikki vosita bilan aytasiz: useTransition va useDeferredValue.
useDeferredValue — qiymatni kechiktirish
import { useState, useDeferredValue, memo } from 'react';
function Katalog({ mahsulotlar }) {
const [qidiruv, setQidiruv] = useState('');
const kechikkanQidiruv = useDeferredValue(qidiruv);
const eskirgan = qidiruv !== kechikkanQidiruv;
return (
<>
<input value={qidiruv} onChange={(e) => setQidiruv(e.target.value)} />
<div style={{ opacity: eskirgan ? 0.6 : 1, transition: 'opacity 0.2s' }}>
<MahsulotRoyxati mahsulotlar={mahsulotlar} qidiruv={kechikkanQidiruv} />
</div>
</>
);
}
const MahsulotRoyxati = memo(function MahsulotRoyxati({ mahsulotlar, qidiruv }) {
const natija = mahsulotlar.filter((m) =>
m.nomi.toLowerCase().includes(qidiruv.toLowerCase())
);
return <ul>{natija.map((m) => <MahsulotQatori key={m.id} mahsulot={m} />)}</ul>;
});
Qanday ishlaydi:
- Harf yozildi →
qidiruv = "nou",kechikkanQidiruvhali"no"(eski) - React darhol render qiladi: input yangi qiymat bilan;
MahsulotRoyxati— eski qiymat bilan →memotufayli o'tkazib yuboriladi → input bir zumda yangilanadi - Keyin fonda
kechikkanQidiruv = "nou"bilan render boshlanadi - Shu paytda yangi harf yozilsa — fondagi render tashlanadi, yangi qiymat bilan qayta boshlanadi
eskirgan — ko'rsatilayotgan ro'yxat hali eski qidiruvga tegishli; uni xiralashtirish foydalanuvchiga "yangilanyapti" deb ko'rsatadi.
[!WARNING]
useDeferredValuefaqat og'ir komponentmemobilan o'ralgan bo'lsa ishlaydi (68-dars).memosizMahsulotRoyxatibirinchi (shoshilinch) render da ham ota-ona bilan birga qayta render bo'ladi — va input yana qotadi. Hisob-kitobni hammemoli komponent ichiga qo'ying, ota-onada emas.
useTransition — yangilanishni "shoshilinch emas" deb belgilash
useDeferredValue — qiymatni olasiz va kechiktirasiz. useTransition — state yangilanishini o'zingiz belgilaysiz:
import { useState, useTransition } from 'react';
function Tablar() {
const [tab, setTab] = useState('umumiy');
const [isPending, startTransition] = useTransition();
function tanla(yangi) {
startTransition(() => {
setTab(yangi); // shoshilinch emas
});
}
return (
<>
<div role="tablist">
<TabTugma faol={tab === 'umumiy'} onClick={() => tanla('umumiy')}>Umumiy</TabTugma>
<TabTugma faol={tab === 'statistika'} onClick={() => tanla('statistika')}>
Statistika
</TabTugma>
</div>
<div style={{ opacity: isPending ? 0.6 : 1 }}>
{tab === 'umumiy' ? <Umumiy /> : <Statistika />} {/* Statistika — og'ir */}
</div>
</>
);
}
startTransition(() => setX(...))— ichidagi yangilanishlar transition: past ustuvorlik, to'xtatilishi mumkinisPending— transition hali bajarilmoqda
Natija: "Statistika" bosildi → eski tab ko'rinib turadi (xira), og'ir tab fonda tayyorlanadi. Shu paytda foydalanuvchi fikrini o'zgartirib "Umumiy" ni bossa — interfeys darhol javob beradi, statistika render i tashlanadi.
Suspense bilan — eski kontentni saqlash
Transition ning yana bir muhim xususiyati — Suspense bilan:
// startTransition siz: yangi tab suspend bo'ladi → kontent skeleton ga almashadi (sakrash)
// startTransition bilan: React eski kontentni ko'rsatib turadi, yangisi tayyor bo'lguncha
Agar yangi kontent suspend bo'lsa (ma'lumot yoki lazy kod yuklanyapti — 81-dars), transition ichida React allaqachon ko'rinib turgan kontentni fallback ga almashtirmaydi — eski ekran isPending bilan qoladi. React Router va Next.js sahifa almashishlarini aynan shuning uchun transition ga o'raydi.
Async transition — React 19
const [isPending, startTransition] = useTransition();
function saqla() {
startTransition(async () => {
await api.saqla(forma); // React 19 da async funksiya ham mumkin
startTransition(() => {
navigate('/royxat');
});
});
}
<button onClick={saqla} disabled={isPending}>
{isPending ? 'Saqlanmoqda...' : 'Saqlash'}
</button>
React 19 da startTransition ga async funksiya berish mumkin — isPending butun async jarayon davomida true. Bu React 19 dagi "Actions" ning asosi.
Qaysi birini tanlash
useTransition |
useDeferredValue |
|
|---|---|---|
| Nimani boshqaradi | State yangilanishini | Qiymatni |
| Qachon | setState ni o'zingiz chaqirasiz |
Qiymat props yoki boshqa hook dan keladi |
| Holat | isPending |
qiymat !== kechikkan |
| Misol | Tab almashtirish, sahifa navigatsiyasi, saralash tugmasi | Qidiruv natijasi, filtr, grafik |
[!INFO] Input ning o'z qiymatini transition ga o'ramang:
startTransition(() => setQidiruv(e.target.value))— input ning o'zi kechikadi va kursor sakrashi mumkin. Input — doim shoshilinch. Transition yoki deferred — faqat undan keyingi og'ir yangilanish uchun.
Debounce dan farqi
Qidiruv uchun debounce ham bor (25-dars). Farqi:
| Debounce | useDeferredValue |
|
|---|---|---|
| Kutish | Qat'iy vaqt (masalan, 300 ms) | Yo'q — kompyuter tez bo'lsa darhol |
| Tez qurilmada | Baribir 300 ms kutadi | Bir zumda |
| Sekin qurilmada | 300 ms + og'ir render — baribir qotishi mumkin | Render to'xtatiladi — input qotmaydi |
| Serverga so'rovlar | ✅ Kamaytiradi | ❌ Kamaytirmaydi |
- Serverga so'rov — debounce (yoki ikkalasi birga)
- Brauzerdagi og'ir render —
useDeferredValue
Nima uchun shunday?
Nima uchun React render ni to'xtatib turish imkoniyati juda muhim?
Chunki JavaScript bir oqimli: brauzer bir vaqtda faqat bitta ishni bajaradi. React 200 ms davom etadigan render ni boshlasa, shu 200 ms davomida brauzer klaviatura bosilishiga, sichqoncha harakatiga, animatsiyalarga javob bera olmaydi — sahifa "muzlaydi". Concurrent rendering bu muammoni ish ni mayda bo'laklarga bo'lib hal qiladi: React har bir kichik bo'lakdan keyin "foydalanuvchi biror narsa qildimi?" deb tekshiradi va kerak bo'lsa joyini bo'shatadi. Bu operatsion tizimlardagi vazifalarni rejalashtirishga o'xshaydi: musiqa pleer hech qachon katta faylni nusxalash tufayli to'xtamasligi kerak. Siz faqat React ga qaysi ish muhimroq ekanini aytasiz — qolganini rejalashtiruvchi o'zi hal qiladi.
Xulosa
Eslab qoling:
- Concurrent rendering — shoshilinch bo'lmagan render to'xtatilishi va tashlanishi mumkin; input qotmaydi
- Shoshilinch: input, bosish, hover. Shoshilinch emas: og'ir ro'yxat, tab kontenti, grafik
useDeferredValue(qiymat)— qiymatning kechiktirilgan nusxasi; og'ir komponentmemobilan bo'lishi shartuseTransition()→[isPending, startTransition];startTransition(() => setX(...))- Transition + Suspense — eski kontent ko'rinib turadi, skeleton ga sakramaydi
- React 19:
startTransition(async () => ...) - Input ning o'z qiymatini transition ga o'ramang
- Server so'rovlari — debounce; brauzerdagi og'ir render — deferred/transition
Keyingi dars
83-dars: Server Components — nima, Client Components dan farqi