1. Kirish: Server holati (Server State) qachon eskiradi
Frontendni boshqarayotganda, foydalanuvchilardan takroran eshitadigan ikkita xabar mavjud. Biri “yangi ro'yxatdan o'tdim, lekin ro'yxatda ko'rinmayapti” va ikkinchisi esa “qoldim, lekin ekranda tiba-tash bo'lib qoldi va yana yuklanib ketdi”dir. Bu ikki alomat bir-biriga aloqador ko'rinmasa-da, aslida bir xil ildizdan kelib chiqadi. Serverning ma'lumotlarini klient “qancha vaqt, qanday mezonlar asosida hali ham amal qiladi deb o'ylaydi” degan kesh (Cache) siyosati yo'qligidadir.
Ko'p jamoalar bu muammoni React Query (hozirgi TanStack Query) yordamida hal qilmoqda va men qatnashayotgan loyiha ham shunday. Biroq, kodni diqqat bilan tahlil qilganda, eng muhim “keshni qancha vaqt saqlab qolish kerak” degan kelishuv bir joyga jamlanmagan va har bir hookda tarqoq holda bo'lishi juda keng tarqalgan.
React Query qiymati “server holati (Server State)” va “klient holati (Client State)”ni farqlashdan boshlanadi. Modal ochilgani kabi qiymatlar ekranning o'ziga tegishli klient holati, lekin ro'yxat, tafsilot va foydalanuvchi ma'lumotlari kabi asl ma'lumot serverda bo'ladi va biz vaqtincha nusxasini olishimiz mumkin. Bu nusxalar men ko'rayotgan vaqt ichida ham serverda o'zgarishi mumkin. Buni useState + useEffect orqali o'z qo'lingiz bilan boshqarish, yuklanish va xato flaglarini to'g'ridan-to'g'ri boshqarishni anglatadi va bir xil ma'lumotlar bir necha ekranlarda chaqirilsa, so'rovlar mantiqan takrorlanadi. React Query esa queryKey degan nom belgisi bilan javoblarni keshga saqlab, bu takrorlanishni o'z zimmaga oladi. Oqibatda “keshni qanday boshqarish” bu kutubxonani to'g'ri foydalanishning asosidir.
2. Asosiy tushunchalar: yangilanish (fresh) va eskirgan (stale), va kesh muddati
2.1 staleTime — ma'lumotning ‘amal qilish muddati’
React Query'dagi barcha ma'lumotlar yangilanish (fresh) yoki eskirgan (stale), ikkita biri. Yaqinda olingan ma'lumot fresh, staleTime o'tganda esa stalega o'zgaradi. Oziq-ovqatning amal qilish muddatiga misol keltirsak yaxshi tushunasiz. Asosiy nuqta shundaki, stale bo'lsa ham ma'lumotlarni yo'qotmaymiz. Amal qilish muddati o'tgan oziq-ovqat ham birinchi navbatda stolda bo'ladi, lekin “keyingi marta xarid qilish imkoniyatim bo'lsa, yangisini olaman” degan belgi qo'yib qo'yamiz. Va bitta tuzoq mavjud. staleTime ning standart qiymati 0 bo'lib, ma'lumotlar qabul qilinishi bilan darhol stale bo'ladi.
2.2 gcTime — keshning ‘ombor saqlash muddati’
Qanday so'rovlarni ishlatayotganingizdan qat'i nazar, komponent ekrandan yo'qolsa, shu so'rov nofaol (inactive) holatga o'tadi. gcTime esa bu nofaol keshni xotiradan tozalashgacha kutadigan vaqt hisoblanadi va standart qiymati 5 daqiqa. Ombor saqlash muddati bilan bog'liq. Bu vaqt ichida shu ekran orqali qaytganingizda, kesh yashayapti va darhol ko'rsatilishi mumkin, agar vaqt o'tsa, chiqindilarni yig'ish (Garbage Collection) obekti bo'ladi va keyingi safar boshlang'ichdan qaytib olinadi.
2.3 Qayta soʻrov (refetch) qachon sodir bo'ladi
stale ma'lumotlar to'rt pallada qayta olinadi. Komponent yangi o'rnatilganda, brauzer oynasi qayta fokusga o'tganda, uzilgan tarmoq yana ulanganda va biz aniq ravishda yo'qotish (Invalidation) chaqirganimizda. Biroq, bu barcha triggerlar faqatgina ma'lumot stale bo'lganda ishlaydi. fresh bo'lsa, oynani qanchalik tez-tez ochib-yopishdan kelib chiqmay, qayta soʻrov bo'lmaydi. Shuning uchun “qanchalik tez-tez qayta olinadi” degan savolning ko'pchiligi staleTime qanday o'rnatilishiga bog'liq.
|
ajratish |
staleTime |
gcTime |
|---|---|---|
|
savol berish |
qanchalik yangiligi |
qanchalik saqlanadi |
|
tugma qiymati |
0 (darhol stale) |
5 daqiqa |
|
ta'sir doirasi |
qayta soʻrov (refetch) vaqti |
xotira egallash / qayta tashrif tezligi |
|
muddati o'tganda |
Ma'lumotlar ekranda qoladi |
Kesh o'zini o'chiradi |
3. Odatda tushiriladigan kesh antipattern
3.1 Umumiy mezonlarsiz staleTime ni har bir hookda tarqatish
Agar umumiy asosiy qiymatni belgilamasangiz, staleTime 0 bo'ladi. Shunday qilib, ekranlarga qaytganingizda, komponent qayta ochilganda, bir xil so'rov yana yuboriladi. Bu haqida keyinchalik xabardor bo'lgan dasturchilar, ekranlar bo'yicha staleTime ni qo'lda bir-ikki joyga kiritishni boshlaydilar, kimdir 1 daqiqa, kimdir 5 daqiqa, aksariyat esa belgilamasdan qoladi. Qiymatga asoslanmaganligi uchun yangi qo'shilgan kishi, “Bu ma'lumotlar qanchalik tez yangilanishi kerak?” degan savolni hal qilish mezonini yo'qotadi.
3.2 So'rov kalitlari va bekor qiluvchi kalitlar muvofiq emas
Eng oddiy va qiyin tutish mumkin bo'lgan haqiqiy xatodir. Masalan, postlar ro'yxatini quyidagi kabi bir kalit bilan kesh qilgan holda, ro'yhatga olingandan so'ng noto'g'ri kalitni bekor qilinishi deb faraz qilaylik.
// 목록은 이 키로 캐싱했는데
useQuery({ queryKey: ['posts'], ... })
// 글 등록 후엔 다른 키를 무효화한다면
queryClient.invalidateQueries({ queryKey: ['postList'] }); // 매칭 안 됨 → 목록 그대로
Ikkita kalit har xil harflarga ega, shuning uchun mos kelmaydi va ro'yxat kesh o'zgarishsiz qoladi. Ro'yxatga olish muvaffaqiyatli, lekin ekran yangilanmaydi. Kompilyator bu ikkita bir xil ma'lumotni ko'rsatishini bilmaydi, shuning uchun hatto ogohlantirish berolmaydi. Qandaydir kichik ko'rinadigan narsa, lekin kalitlarni satr sifatida o'z qo'li bilan yozish har qanday loyihada takrorlanadigan xato hisoblanadi. Haqiqatan ham, men ko'rgan kodlar orasida bir xil fayl ichida o'chirilganda to'g'ri kalit, ro'yhatga olishda esa noto'g'ri kalitni bekor qilib “o'chirish amalga oshiriladi, lekin ro'yhatga olish ekranda ko'rinmaydi” nozik xato mavjud bo'lganida ko'rganman.
3.3 Kesh tashqarisidagi qo'lda olish mavjud
Ba'zi ekranlar React Query bilan, boshqa ekranlar esa hali ham useState va useEffect yordamida bir xil ma'lumotlarni olish holati. Shunday qilib, bitta tomonda kesh bo'lib, ma'lumotlar bir-biriga mos kelmasligi va takrorlanishni olib tashlash va avtomatik yangilanishdan afzalliklar ushbu ekranda yo'qoladi. Migratsiya tugamagan kod bazasida ayniqsa tez-tez uchraydi.
4. Samara keshni boshqarish strategiyasi
4.1 Umumiy asosiy qiymatlar (Default Options) bilan kelishuv
Eng avvalo bajarilishi kerak boʻlgan ish bu QueryClient ning defaultOptionsga keshning mezonini belgilashdir. staleTime ni 0 bo'lmagan mantiqiy qiymat bilan o'rnatish va refetchOnWindowFocusumumiy holda o'chirib, real vaqti talab qilinadigan ekranlarda faqat istisno tariqasida yoqishni tavsiya qilamiz. Ushbu bir martalik sozlama bilan 3.1 tartibga solinadi va alohida hooklarda bir xil variantlarni takroran yozish zarurati yo'qoladi.
new QueryClient({
defaultOptions: {
queries: {
staleTime: 1000 * 30, // 기준선: 30초 동안은 신선하다고 본다
refetchOnWindowFocus: false, // 기본은 끄고, 필요한 화면만 켠다
retry: 1, // 실패 시 과한 재시도 방지
},
},
});
Raqamning o'zidan ko'ra, muhim bo'lgan narsa “asos chizig'i kodning bir nuqtasida mavjud” boʻlishidir. Endi alohida hooklar faqat asos chizig'idan farqli ravishda harakat qilish kerak bo'lgan paytlarda opsiyalarni o'zgartirishlari kerak, va o'zgartirilgan joy “bu ma'lumot maxsus” degan signal bo'ladi.
4.2 Ma'lumotlarning tabiati bo'yicha staleTimeni tasniflash
“staleTimeni necha daqiqaga belgilashim kerak” har bir ekran uchun belgilanmasligi kerak. Asosiy mezon ekran emas, balki ma'lumotning qanchalik tez-tez o'zgarayotganidir. Agar ma'lumotlarni uch turga bo'lib qo'ysangiz, yangi so'rovlar yaratishda xavotir kamayadi. Master ma'lumotlari kabi deyarli o'zgarmaydigan qiymatlar staleTimeni uzoq (ba'zida Infinitygacha) qo'yish va shu bilan “qiymat haqiqatan ham o'zgaradigan paytda bevosita bekor qilamiz” degan va'dani olib yurish samaraliroq bo'ladi. Shunda odatda tarmoqdan foydalanmay, haqiqatan o'zgarishi kerak bo'lgan paytda bir marta yangilaydi. gcTime odatda asosiy 5 daqiqa yetarlidir, ammo kiosk yoki embedded kabi bir ekran ustida uzoq vaqt qolish sharoitida uni oshirib “qaytganda yana yuklanishdan” qochish va xotira siqilgan muhitda uni kamaytira turib ongli ravishda sozlash kerak.
|
tasniflash |
namuna |
tavsiya etilgan staleTime |
|---|---|---|
|
master (deyarli o'zgarmas) |
kategoriya, kod jadvali, tashkilot/bog'lanish tuzilmasi |
5~10 daqiqa yoki undan ko'p + o'zgarilganida bevosita bekor qilish |
|
yarim statik (ba'zan o'zgaradigan) |
menda profilim, ruxsatlar·sozlamalar |
1~3 daqiqa |
|
transaktsion (tez-tez o'zgaradigan) |
Buyurtma/yangiliklar ro'yxati, eslatmalar, zaxira |
0~30 soniya |
4.3 so'rov kaliti 'fabrika' ga birlashtiriladi
3.2 kalitlariga mos kelmaslik xatosini tuzatish usuli oddiy. Kalitni qo'lda yozmasdan, kalitni yaratuvchi funksiya (fabrika) orqali o'tkazish kerak. Qat'iy ravishda loyihalashtirilsa, bekor qilish ancha kuchli bo'ladi.
export const postKeys = {
all: ['posts'] as const,
lists: () => [...postKeys.all, 'list'] as const,
list: (filters) => [...postKeys.lists(), filters] as const,
detail: (id) => [...postKeys.all, 'detail', id] as const,
};
Bu yerda bitta mexanizmni bilish foydali bo'ladi.invalidateQuerieskalitning 'qismiy moslik (prefix match)' orqali ishlaydi. Ya'ni invalidateQueries({ queryKey: postKeys.all })bitta qator bilan ['posts','list', ...] da kesh qilingan barcha ro'yxatlar va tafsilotlar bir vaqtning o'zida o'zgaradi. Aksincha, faqat bitta maqolani yangilamoqchi bo'lsangiz, postKeys.detail(id)ni bekor qilish kifoya. O'qish ham, bekor qilish ham bir xil fabrika orqali kalitni olishi sababli, harf xatolari yuzaga kelishidan butunlay qochiladi. Kalit faqat bitta joyda belgilanganligi sababli avtomatik to'ldirish va turdagi tekshirish yordamida ham foydalanish mumkin.
4.4 Bekor qilishdan boshqa yechim yo'q: to'g'ridan-to'g'ri yangilash va optimistik yangilash
Bekor qilish (invalidate) bu 'bu kesh eski, uni qaytadan olib kel' degan ko'rsatma. Xavfsiz, ammo yana bir marta tarmoq so'rovini uyg'otadi. Ammo agar o'zgarish API javobida allaqachon eng so'nggi ma'lumot bo'lsa, qayta olishi shart emas.setQueryDataTo'g'ridan-to'g'ri keshni almashtirish tez va samarali. Bu bir marta so'rovni to'liq tejash demak.
Yana bir qadam oldinga o'tib, like tugmasi yoki belgilash qutisi kabi darhol javob berishi muhim bo'lgan harakatlar uchun optimistik yangilashni (Optimistic Update) qo'llaymiz.onMutateQadamda server javobini kutmasdan keshni oldindan o'zgartirib, ekran darhol yangilanadi va agar so'rov muvaffaqiyatsiz bo'lsa, oldingi qiymatga qaytariladi. Foydalanuvchi kechikishni deyarli his etmaydi. Xulosa qilib aytganda, ‘qaytadan olish (invalidate) → javob bilan almashtirish (setQueryData) → oldindan o'zgartirib, muvaffaqiyatsiz bo'lsa, qaytarish (optimistic)’ tartibda, darholik muhimroq bo'lsa, o'ngni tanlash kerak.
4.5 O'tishni silliq qilish: keepPreviousData va placeholderData
Sahifalash yoki qidiruv kabi bir xil ekranda parametrlar o'zgaradigan hollarda, kalit har safar o'zgarganda ekran bo'sh holatga keladi va aylantiruvchi yordam beradi. Bu vaqtda placeholderData: keepPreviousDataberilganda yangi ma'lumot kelguncha avvalgi sahifaning ma'lumotlarini ko'rsatadi. Jadval yo'qolmaydi va tabiiy ravishda keyingi sahifaga o'tadi. Ro'yxat va qidiruv UI-da tajribani eng arzon ko'tarish usuli bo'lib, allaqachon yaxshi ishlatib bo'lsangiz, boshqa ro'yxatlarga kengaytirishni tavsiya qilamiz.
4.6 Kutishni oldindan yashirish: prefetch va initialData
Foydalanuvchi keyin nima ko'rishini oldindan aytib bera oladigan bo'lsa, ushbu ma'lumotni oldindan qabul qilishimiz mumkin. Ro'yxatda qandaydir elementga sichqoncha bilan bosgan paytda prefetchQuerybilan tafsilotlarni oldindan qabul qiladigan bo'lsak, haqiqatan ham bosilganda allaqachon keshda bor bo'ladi va darhol ochiladi. Aksincha, agar allaqachon qo'lga olingan ma'lumot bo'lsa (ro'yxat javobida tafsilotlar qismi kiritilgan bo'lsa yoki SSR bilan yuklangan bo'lsa), initialDatabilan keshning boshlang'ich qiymatini to'ldirib, birinchi yuklashni o'tkazib yuborishimiz mumkin. Ikkalasi ham “kutish vaqtini foydalanuvchi ko'zi bilan ko'rilmaydigan joyga ko'chirish” texnikasidir.
4.7 Keshni ko'z bilan ko'rish: Devtools
Oxirgi marta, faqat rivojlantirish qurilmasida @tanstack/react-query-devtoolsbog'lashni qat'iyan tavsiya qilaman. Har bir so'rovning fresh·stale·inactive dan qaysi holatda ekanligini, invalidatsiya haqiqatan ham amalga oshganligini, qaysi kalitlar qancha ko'tarilganini tasvir orqali ko'rsatadi. 3.2 kabi kalit nizo Devtoolsni bir marta ochib ko'rganingizda darhol ajralib chiqadi. Taxmin orqali da'vo qilingan kesh muammosini, ko'z bilan tasdiqlash muammosi bilan o'zgartiradi.
5. Xulosa
React Query'dan to'g'ri foydalanish - bu ajoyib funksiyalarni ko'p ishlatish emas, balki keshga oid va'dalarni kodning bir joyida aniq qilib belgilashdir. Birinchidan, global standartlarni belgilab, vaqti kelganda asosni yaratish, ikkinchidan, ma'lumotlarning xususiyatiga ko'ra staleTime'ni tasniflash va uchinchidan, so'rov kalitlarini fabrikaga jamlash. Ushbu uchta holat bilan “ro'yxatga olganimdan keyin ro'yxat o'zgarmayapti”, “ekranda har gal ko'chirganda mayda chiroqlar yoqilyapti” kabi alomatlarning ko'pchiligi yo'qoladi.
Buning ustiga yana bir qatlam qo’shish samaradorlikdir. Har bir o'zgarishni invalidatsiya sifatida qayta ko'rib chiqish o'rniga, javob bilan keshni to'g'ridan-to'g'ri yangilab (setQueryData), darhol zarur joylarda optimistik yangilanish bilan ishlang va bashorat qilinadigan keyingi ekranlarni oldindan oling (prefetch). Keshni “qachon tozalash?” masalasi emas, “qachon va qanday to'ldirish?” masalasiga qaraganingizda, bir xil server va bir xil tarmoq ustida ham ko'proq tez va sokin funktsiyalarning ekranini yaratishingiz mumkin. Oxir-oqibat yaxshi kesh strategiyasi - bu foydalanuvchini kutish hisini bermaslikdir.
Ma'lumotlar
-
TanStack Query – Muhim Standartlar — https://tanstack.com/query/latest/docs/framework/react/guides/important-defaults
-
TanStack Query – Kesh Mexanizmi — https://tanstack.com/query/latest/docs/framework/react/guides/caching
-
TanStack Query – So'rovni Invalidatsiya qilish — https://tanstack.com/query/latest/docs/framework/react/guides/query-invalidation
-
TanStack Query – Optimistik Yangilanishlar — https://tanstack.com/query/latest/docs/framework/react/guides/optimistic-updates
-
TanStack Query – Oldindan yuklash — https://tanstack.com/query/latest/docs/framework/react/guides/prefetching
-
TkDodo – Samarali React Query Kalitlari — https://tkdodo.eu/blog/effective-react-query-keys
-
TkDodo – Amaliy React Query — https://tkdodo.eu/blog/practical-react-query
toffeeman