Ana içeriğe geç
SYS:ONLINEMODE:PORTFOLIOLOCAL:--:--:--

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

30 Temmuz 2026
1
TanStack Query prefetching — a data capsule reaching the cache before the product detail view opens

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
Normal veri isteği ve prefetch akışında isteğin hangi anda başladığını karşılaştıran zaman çizelgesi
Normal akış isteği component render edildikten sonra başlatır. Prefetch, aynı query’yi focus veya hover sinyaliyle daha erkene alır; veri render anına kadar hazır olabilir veya istek o sırada devam edebilir.

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ıca invalidateQueries ile 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’in useQuery ile 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 staleTime beklemeyi 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:

  1. Hiç beklemeden tıklayın: istek navigasyondan önce başlamış mı?
  2. Prefetch tamamlandıktan sonra tıklayın: detay query’si cache verisini hemen gösterebiliyor mu?
  3. staleTime dolduktan 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 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.

Kategoriler

TanStack QueryReactPerformance

Bültenime abone olun

Yeni yazılar ve ara sıra ürün güncellemeleri için bültenime abone olun.

Bu Yazıyı Paylaş

Yazar Hakkında

Enes Kaymaz

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
Yorumlar yükleniyor...

Bültenime abone olun

Tasarım, geliştirme ve teknoloji trendleri hakkında en son güncellemeleri alın.