TanStack Query Prefetching Nedir? Veriyi Tıklamadan Önce Getirmek

Sorun API hızı değil, isteğin başlama anı
React uygulamasındaki her bekleme yavaş bir API’den kaynaklanmaz. Bazen sunucu yeterince hızlı cevap verir; fakat uygulama isteği gereğinden geç başlatır. Kullanıcı bir listedeki ürünü incelemeye karar vermiştir, uygulama ise detay verisini istemek için yeni sayfanın render edilmesini bekler.
Bu küçük zamanlama farkı özellikle liste–detay akışlarında hissedilir. Ürünler, yazılar veya projeler ekranda zaten görünürken kullanıcının bir sonraki adımı hakkında bazı sinyaller de vardır: bağlantıya klavyeyle odaklanması, fareyi kartın üzerine getirmesi ya da route geçişinin başlaması gibi. Veri isteği bu sinyallerden biriyle erkene alınabilirse yeni ekran boş bir cache ile açılmak zorunda kalmaz.
TanStack Query, React uygulamalarında sunucudan gelen veriyi isteme, cache’leme ve güncel tutma işini yöneten bir kütüphane. Prefetching ise ileride gerekmesi muhtemel veriyi component kullanmadan önce getirip bu cache’e yerleştirmek demek.
Prefetching API’yi hızlandırmaz; beklemeyi daha erken başlatır. Kullanıcı gerçekten detay ekranına giderse veri hazır olabilir. Gitmezse indirilmiş ama kullanılmamış bir cevap kalır. Bu nedenle asıl soru “Nerede prefetch ekleyebilirim?” değil, “Bir sonraki veri ihtiyacını nerede yeterince güvenle tahmin edebilirim?”
Bu rehber, TanStack Query’nin güncel React dokümantasyonundaki prefetchQuery, cache ve router davranışlarını temel alıyor. Amaç her olası API’yi sıralamak değil; ilk prefetch kararını doğru kurmak.
Prefetching nasıl çalışır?
Normal akışta detay verisi, detay component’i render edildiğinde useQuery tarafından istenir. Prefetch kullandığınızda aynı sorgu daha önce, uygulamanın query cache’ini yöneten QueryClient üzerinden çalışır. Sonuç bellekteki query cache’e yazılır. Detay component’i daha sonra aynı queryKey, yani aynı cache anahtarıyla açılırsa hazırlanmış sonucu bulur.
| An | Prefetch yok | Prefetch var |
|---|---|---|
| Kullanıcı karta odaklanır | İstek başlamaz | Detay isteği başlayabilir |
| Kullanıcı tıklar | Route değişimi başlar | Route değişimi başlar; istek sürüyor veya bitmiş olabilir |
| Detay component’i render edilir | İstek şimdi başlar | Aynı key’deki cache sonucu kullanılır |
Resmî prefetching rehberine göre sonuç, normal bir query gibi cache’lenir. Prefetch çağrısı veriyi component’e döndürmez; görevi veriyi ileride kullanılması için hazırlamaktır.
“Aynı query” ifadesi burada kritik. Liste kartında ['product', productId], detay sayfasında yalnızca ['product'] kullanırsanız iki ayrı cache kaydı oluşur. Prefetch tamamlanmış olsa bile detay ekranı onu bulamaz. TanStack Query cache’i query key üzerinden ayırır; query function’ın sonucunu değiştiren kimlik, filtre veya sayfa numarası da key’in parçası olmalıdır.
İlk uygulama: hover ve klavye odağında detay verisini getir
Tek bir yerde query key yazıp iki yerde aynı kaldığını ummak yerine query seçeneklerini ortak bir fonksiyonda toplamak daha güvenli:
import {
queryOptions,
useQuery,
useQueryClient,
} from '@tanstack/react-query'
function productQuery(productId: string) {
return queryOptions({
queryKey: ['product', productId],
queryFn: () => fetchProduct(productId),
staleTime: 60_000,
})
}
Ürün bağlantısı, kullanıcının niyetini fare veya klavye üzerinden gördüğünde bu sorguyu hazırlayabilir:
function ProductLink({
productId,
children,
}: {
productId: string
children: React.ReactNode
}) {
const queryClient = useQueryClient()
const prefetchProduct = () => {
void queryClient.prefetchQuery(productQuery(productId))
}
return (
<a
href={`/products/${productId}`}
onMouseEnter={prefetchProduct}
onFocus={prefetchProduct}
>
{children}
</a>
)
}
Detay ekranı aynı options üreticisini kullandığında query key, fetch fonksiyonu ve freshness kararı da ortak kalır:
function ProductDetail({ productId }: { productId: string }) {
const product = useQuery(productQuery(productId))
if (product.isPending) return <ProductSkeleton />
if (product.isError) return <ProductError />
return <ProductView product={product.data} />
}
onFocus yalnız erişilebilirlik ayrıntısı değil. Fare kullanmayan biri linke Tab ile geldiğinde de aynı hazırlık yapılır. Dokunmatik ekranda hover’a güvenemeyeceğiniz için route loader, görünürlük veya navigasyon başlangıcı gibi başka bir sinyal gerekebilir. Hangi sinyalin doğru olduğu, arayüzünüzde “bu veri birazdan gerekecek” tahminini hangisinin daha iyi yaptığına bağlı.
staleTime ile gcTime aynı süreyi ölçmez
Prefetching’in en sık karıştırılan kısmı iki ayrı zaman ayarıdır:
staleTime: Verinin ne kadar süre güncel, yani fresh kabul edileceğini belirler. Query ayrıcainvalidateQueriesile manuel olarak geçersiz işaretlenmemişse bu süre dolmadan eskime kaynaklı yeni fetch başlatılmaz.gcTime: Artık hiçbir aktif component’inuseQueryile izlemediği query’nin cache’de ne kadar tutulacağını belirler. Süre dolunca kayıt garbage collection ile kaldırılabilir.
TanStack Query’nin güncel varsayılanlarında cache verisi hemen stale kabul ediliyor; inaktif query ise varsayılan olarak beş dakika sonra cache’den kaldırılıyor. Bu iki sonuç farklıdır. Stale veri cache’de durabilir ve ekranda hemen gösterilirken arka planda yeniden fetch edilebilir. Garbage collection olmuş veri ise artık cache’de yoktur; component yeniden boş yükleme durumundan başlar.
Resmî rehber ayrıca prefetch çağrısına verdiğiniz staleTime değerinin sonraki useQuery çağrısına kendiliğinden taşınmadığını özellikle belirtiyor. Yukarıdaki productQuery gibi ortak options kullanmak bu ayrılığı önler.
Her veri için ezbere bir dakika seçmek doğru değil. Ürün açıklaması nadiren değişiyorsa daha uzun bir freshness penceresi mantıklı olabilir. Stok, açık artırma veya anlık durum gibi hızla değişen veride aynı süre yanıltıcı sonuç gösterebilir. staleTime, performans ayarından önce ürünün “ne kadar eski veri kabul edilebilir?” kararıdır.
prefetchQuery, fetchQuery ve ensureQueryData farkı
Bu metotların hepsi cache ile konuşur fakat çağıran kodla yaptıkları sözleşme aynı değildir:
| Metot | Ne döndürür? | Hata davranışı | Uygun durum |
|---|---|---|---|
prefetchQuery |
Promise<void> |
Hata fırlatmaz | Sonucu şimdi kullanmadan, sonraki ekran için cache’i hazırlamak |
fetchQuery |
Query verisi | Başarısızlıkta hata fırlatır | Veriyi mevcut akışta kullanmak veya kritik hatayı yakalamak |
ensureQueryData |
Cache’deki veya getirilen veri | Fetch gerekiyorsa hatayı iletebilir | “Cache’de varsa kullan, yoksa getir ve bana sonucu ver” akışı |
setQueryData |
Cache’e yazılan veri | Ağ isteği yapmaz | Veri zaten senkron olarak eldeyse cache’i doğrudan doldurmak |
QueryClient referansında prefetchQuery için bu hata davranışı bilinçli bir graceful fallback olarak açıklanıyor. Hover sırasında istek başarısız olursa etkileşimi hata ekranına çevirmek yerine, gerçek useQuery açıldığında sorgu yeniden denenebilir.
Fakat bir route’un render edilip edilmeyeceğine veri sonucuyla karar veriyorsanız bu sessizlik uygun değildir. Örneğin bulunamayan ürün için 404 üretmeniz gerekiyorsa sonucu ve hatayı görebileceğiniz fetchQuery daha doğru sözleşmedir.
Prefetching request waterfall’ı ne zaman düzleştirir?
Bir makale component’inin önce makaleyi, render edildikten sonra altındaki yorum component’inin yorumları istediğini düşünün. Yorum isteği makale isteğinin sonucuna bağlı değilse buna rağmen iki istek sıraya girmiş olur:
1. |----- makale -----|
2. |----- yorumlar -----|
Yorum sorgusunu üst component’te veya route seviyesinde erkenden başlatmak iki isteği paralelleştirebilir:
1. |----- makale -----|
1. |----- yorumlar ----------|
Resmî request waterfall rehberi, component içinde veri fetch etmenin başlıca performans risklerinden biri olarak bu sıralı yapıyı gösteriyor. Prefetching burada gecikmeyi saklamaktan fazlasını yapar; gereksiz bağımlılığı kaldırarak toplam bekleme yolunu kısaltabilir.
Ama ikinci sorgu gerçekten birincinin sonucuna bağlıysa aynı hile çalışmaz. Önce kullanıcı kaydından userId alıp sonra o kimlikle proje istemek zorundaysanız veri bağımlılığı gerçektir. Çözüm bazen backend’in iki cevabı tek endpoint’te birleştirmesi, bazen de ilk cevabın ikinci isteği başlatacak kimliği daha erken sağlamasıdır. Prefetching, bilinmeyen parametreyi tahmin edemez.
Component, Suspense, router ve server: prefetch nerede başlamalı?
Doğru katman, veriye ne zaman ihtiyaç duyacağınızı nerede bildiğinize bağlıdır.
Event handler
Hover ve focus örneği, kullanıcının niyetini gördüğünüz ama navigasyonu henüz başlatmadığınız durum için uygun. Uygulaması küçük, geri alınması kolay ve tek bir akışta ölçülebilir.
Component yaşam döngüsü
Üst component, daha sonra açılacak bir alt component’in veriye kesinlikle ihtiyaç duyacağını biliyorsa sorguyu erken başlatabilir. Normal query kullanan bir ağaçta sonucu kullanmadan useQuery çağırmak; Suspense kullanan yapıda ise sınırdan önce usePrefetchQuery çalıştırmak resmî rehberdeki seçenekler arasında.
useEffect de prefetch başlatabilir, fakat aynı component’teki bir Suspense query render’ı durduruyorsa effect ancak o sorgu çözüldükten sonra çalışır. Yani tam kaldırmak istediğiniz sıralı beklemeyi koruyabilir.
Router
Route’a girildiği anda hangi verilerin gerekeceği belliyse loader katmanı component ağacından daha erken davranabilir. Burada bütün veriyi aynı şekilde beklemek zorunda değilsiniz. Sayfanın kimliğini belirleyen kritik query beklenebilir; yorumlar veya öneriler gibi ikincil veriler başlatılıp beklenmeden render’a geçilebilir.
Bu ayrım ürün kararını görünür yapar: “Bu veri olmadan sayfa anlamsız mı, yoksa bölüm biraz sonra gelebilir mi?” Router entegrasyonunun değeri yalnız hız değil, bu cevabı component’lere dağılmış yan etkiler yerine route sözleşmesinde toplamasıdır.
Server rendering ve hydration
Server’da prefetch edilen başarılı query’ler dehydrate ile seri hale getirilip istemcide HydrationBoundary üzerinden cache’e taşınabilir. TanStack Query’nin SSR rehberi, istemci açılır açılmaz aynı verinin tekrar istenmesini önlemek için server rendering kullanılan QueryClient’ta sıfırdan büyük bir varsayılan staleTime öneriyor.
Server tarafında QueryClient’ın istekler arasında paylaşılmaması da önemli. Cache’in kullanıcılar arasında sızmaması için her server isteğinin kendi QueryClient örneği olmalı. Uygulama biçimi Next.js, Remix veya kullandığınız router’a göre değişir; prefetching rehberi framework’ün veri ve cache sınırlarının yerine geçmez.
Infinite query için kaç sayfa önceden getirilmeli?
prefetchInfiniteQuery varsayılan olarak ilk sayfayı hazırlar. Birden fazla sayfa için pages ile birlikte sonraki cursor’ı üreten getNextPageParam gerekir:
await queryClient.prefetchInfiniteQuery({
queryKey: ['projects'],
queryFn: fetchProjects,
initialPageParam: 0,
getNextPageParam: (lastPage) => lastPage.nextCursor,
pages: 2,
})
Üç sayfayı indirebilmek, üçünü de indirmenin doğru olduğu anlamına gelmez. Her ek sayfa daha fazla ağ, backend ve cache maliyeti taşır. Kullanıcıların çoğu yalnızca ilk ekranı görüyorsa sonraki iki sayfayı hazırlamak performans yatırımı değil, kullanılmayan veri transferidir. Sayfa sayısını tahminle değil gerçek gezinme oranı ve payload büyüklüğüyle belirleyin.
Prefetching ne zaman yanlış optimizasyondur?
- Niyet zayıfsa: Uzun bir listede fare her kartın üzerinden geçerken onlarca detay isteği başlatmak, tıklama olasılığı düşük veriyi indirir.
- Payload büyükse: Harita, rapor, medya veya geniş analitik cevapları mobil bağlantıda görünmeden indirmek kullanıcıya doğrudan maliyet çıkarabilir.
- Veri çok hızlı değişiyorsa: Uzun
staleTimebeklemeyi azaltırken kabul edilemeyecek kadar eski bilgi gösterebilir. - Query key eksikse: Kullanıcı, dil, filtre veya yetki kapsamını key’e katmamak yanlış cache sonucunu eşleştirebilir. Yetkilendirme yine backend’de yapılmalıdır; cache key güvenlik sınırı değildir.
- Asıl sorun backend ise: Beş saniyelik endpoint’i hover ile iki saniye erken başlatmak yalnızca gecikmenin bir bölümünü gizler. Sorgu, indeks veya payload problemi çözülmüş olmaz.
- Ölçüm yoksa: Kullanıcı zaten hiç beklemiyorsa ek karmaşıklık ve trafik anlamlı bir kazanım üretmeyebilir.
Prefetching en iyi, olasılığı yüksek ve boyutu ölçülü bir sonraki adımda çalışır. “Belki gerekir” diye bütün uygulamayı önceden indirmek cache stratejisi değil, tahminsiz eager loading olur.
İlk denemeyi nasıl ölçmelisiniz?
Tek bir detay akışı seçin. Önce tarayıcının Network panelinde istek başlangıcını ve detay ekranının boş yükleme süresini kaydedin. Ardından hover/focus prefetch ekleyip üç ayrı durumu deneyin:
- Hiç beklemeden tıklayın: istek navigasyondan önce başlamış mı?
- Prefetch tamamlandıktan sonra tıklayın: detay query’si cache verisini hemen gösterebiliyor mu?
staleTimedolduktan sonra tıklayın: ekranda cache verisi görünürken arka plan refetch davranışı beklendiği gibi mi?
TanStack Query Devtools ile query’nin key’ini, fresh/stale durumunu ve cache’de kalıp kalmadığını kontrol edin. Ayrıca başarısız prefetch’i, yavaş bağlantıyı ve kullanıcı tıklamadan karttan ayrıldığında oluşan kullanılmamış isteği görün. Yalnızca başarılı hızlı bağlantı demosu, optimizasyonun maliyetini göstermez.
Uygulama kararı
Prefetching’e bütün route’ları kapsayan bir altyapı işi olarak başlamayın. Yüksek olasılıkla açılan, verisi küçük ve query key’i açık olan tek bir detay ekranı seçin. Query seçeneklerini ortaklaştırın, hem fare hem klavye niyetini yakalayın ve sonucu ağ panelinde ölçün.
Kazanç varsa aynı modeli router veya component seviyesinde gerçekten tekrar eden beklemelere taşıyabilirsiniz. Kazanç yoksa kaldırmak da doğru sonuçtur. Prefetching’in başarısı kaç sorguyu erkenden başlattığınızla değil, kullanılmayan veri transferini büyütmeden kaç gerçek bekleme anını ortadan kaldırdığınızla ölçülür.
Birincil kaynaklar
- TanStack Query: Prefetching & Router Integration
- TanStack Query: Performance & Request Waterfalls
- TanStack Query: Important Defaults
- TanStack Query: Query Keys
- TanStack Query: QueryClient API reference
- TanStack Query: Server Rendering & Hydration
TanStack Query davranışları ve bağlantılar 30 Temmuz 2026 tarihinde resmî v5 React dokümantasyonundan kontrol edildi. Kütüphane sürümü değiştiğinde özellikle cache varsayılanlarını, router örneklerini ve SSR önerilerini yeniden doğrulayın.
Yazar Hakkında

Enes Kaymaz
Enes Kaymaz
Tasarım yapıyor, kod yazıyor, arada bunlardan ürün çıkarıyor.
Hakkımda Daha Fazla Bilgi →İlgili Yazılar
Tümünü Gör →
Next.js Nerede Çalışmalı? Vercel ile Coolify + VPS Arasındaki Gerçek Fark
Vercel ile Coolify kurulu bir VPS’in gerçekte neyi yönettiğini, neye mal olduğunu ve hangi riskleri size bıraktığını kaynaklarıyla karşılaştırın.
Devamını Oku →
Framer mı Next.js mi? Portfolyo, SaaS, E-ticaret ve Landing Page İçin 2026 Rehberi
Framer ve Next.js gerçekte ne yapar; portfolyo, uygulama, mağaza veya landing page için hangisi ne zaman doğru seçimdir?
Devamını Oku →Bültenime abone olun
Tasarım, geliştirme ve teknoloji trendleri hakkında en son güncellemeleri alın.