Takip et

QueryClient’ı Uzmanlaşmak: React Query’nin Beyni (Kapsamlı Rehber)

QueryClient’ı Uzmanlaşmak: React Query’nin Beyni (Kapsamlı Rehber) Modern web uygulamalarında veri yönetimi ve API çağrıları, kullanıcı deneyimin…

QueryClient’ı Uzmanlaşmak: React Query’nin Beyni (Kapsamlı Rehber)

Modern web uygulamalarında veri yönetimi ve API çağrıları, kullanıcı deneyimini doğrudan etkileyen kritik unsurlardır. React Query, bu karmaşık süreci basitleştirerek performanslı ve sürdürülebilir uygulamalar geliştirmemizi sağlayan güçlü bir kütüphanedir. Bu gücün merkezinde ise tüm veri akışını, önbelleklemeyi ve senkronizasyonu yöneten QueryClient yer alır. Bu makalede, QueryClient‘ın derinliklerine inerek, onun ne olduğunu, nasıl çalıştığını ve React Query uygulamalarınızda ondan en iyi şekilde nasıl faydalanabileceğinizi kapsamlı bir şekilde inceleyeceğiz.

QueryClient Nedir ve Neden Önemlidir?

QueryClient, React Query ekosisteminin kalbi ve beynidir. Uygulamanızdaki tüm sorguların (queries), mutasyonların (mutations) ve önbelleklenen verilerin yönetiminden sorumlu merkezi bir depodur. Geliştiricilerin manuel olarak yapması gereken veri getirme, önbellekleme, senkronizasyon, hata yönetimi ve arka plan güncellemeleri gibi birçok karmaşık görevi otomatikleştirir. Bu sayede, uygulamanızın veri katmanını düşünmek yerine, kullanıcı arayüzünüze odaklanabilirsiniz.

React Query Mimarisi İçindeki Yeri

QueryClient, uygulamanızın kök bileşenine yakın bir yerde QueryClientProvider aracılığıyla sağlanır. Bu sağlayıcı, React bağlam (context) mekanizmasını kullanarak QueryClient örneğini tüm alt bileşenlere erişilebilir kılar. Böylece, useQuery, useMutation gibi hook’lar bu merkezi istemci üzerinden verilere erişebilir, güncelleyebilir ve önbellekleme politikalarını uygulayabilir.

Merkezi Veri Yönetimi Rolü

QueryClient, uygulamanızın veri durumunu tek bir yerde tutar. Bu, farklı bileşenlerin aynı veriye tutarlı bir şekilde erişmesini sağlar. Bir veri güncellendiğinde, QueryClient otomatik olarak bu veriyi kullanan tüm bileşenleri yeniden render etmeden günceller. Bu merkezi yönetim, özellikle büyük ve karmaşık uygulamalarda veri tutarlılığını sağlamanın ve hataları azaltmanın anahtarıdır.

Geliştirici Deneyimine Katkıları

QueryClient‘ın sağladığı otomasyon, geliştiricilerin hayatını büyük ölçüde kolaylaştırır. Manuel önbellekleme mantığı yazmaktan, race condition’larla uğraşmaktan veya stale verilerle başa çıkmaktan kurtulursunuz. Deklaratif API’si sayesinde, veri akışını yönetmek sezgisel ve hatasız hale gelir. Bu da daha hızlı geliştirme süreçleri ve daha az hata anlamına gelir.

QueryClient Kurulumu ve Yapılandırması

QueryClient‘ı kullanmaya başlamak oldukça basittir, ancak uygulamanızın ihtiyaçlarına göre özelleştirmek, performans ve esneklik açısından kritik öneme sahiptir.

Temel Kurulum Adımları (QueryClientProvider)

React uygulamanızda QueryClient‘ı kullanmak için öncelikle bir QueryClient örneği oluşturmalı ve bunu QueryClientProvider bileşeni aracılığıyla uygulamanızın köküne sağlamalısınız.

// App.jsx veya index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import {
  QueryClient,
  QueryClientProvider,
} from '@tanstack/react-query';
import App from './App';

// Yeni bir QueryClient örneği oluşturun
const queryClient = new QueryClient();

ReactDOM.createRoot(document.getElementById('root')).render(
  
    
      
    
  ,
);


Bu kurulum, uygulamanızdaki tüm React Query hook'larının bu queryClient örneğine erişmesini sağlar.

Varsayılan Ayarların Özelleştirilmesi (defaultOptions)

QueryClient oluştururken, tüm sorgular ve mutasyonlar için geçerli olacak varsayılan ayarları defaultOptions özelliği aracılığıyla belirleyebilirsiniz. Bu, uygulamanız genelinde tutarlı bir davranış sağlamak için çok kullanışlıdır.

const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      staleTime: 1000 * 60 * 5, // 5 dakika sonra veriyi "stale" olarak işaretle
      cacheTime: 1000 * 60 * 10, // 10 dakika sonra kullanılmayan veriyi cache'ten sil
      refetchOnWindowFocus: false, // Pencereye odaklanıldığında otomatik refetch yapma
      retry: 3, // Hata durumunda 3 kez yeniden dene
    },
    mutations: {
      // Mutasyonlar için varsayılan ayarlar buraya eklenebilir
    },
  },
});


Bu ayarlar, her bir useQuery veya useMutation çağrısında ayrı ayrı belirtmek yerine, global olarak uygulanır. Ancak, her bir hook içinde bu ayarları geçersiz kılmak da mümkündür.

Birden Fazla QueryClient Kullanımı

Çoğu durumda tek bir QueryClient yeterli olsa da, bazı gelişmiş senaryolarda birden fazla QueryClient kullanmak isteyebilirsiniz. Örneğin, uygulamanızın farklı bölümleri tamamen farklı önbellekleme politikaları veya veri kaynakları gerektiriyorsa. Bu durumda, farklı QueryClientProvider'ları farklı client prop'larıyla sarmalayarak bunu başarabilirsiniz.

// App.jsx
function App() {
  const adminQueryClient = new QueryClient({ /* admin options */ });
  const publicQueryClient = new QueryClient({ /* public options */ });

  return (
    <>
      
        
      
      
        
      
    >
  );
}


Bu yaklaşım, her bir QueryClient'ın kendi izole önbellek ve yapılandırma setine sahip olmasını sağlar.

Veri Yönetimi ve Cache Mekanizmaları

QueryClient'ın en güçlü yönlerinden biri, gelişmiş önbellekleme ve veri yönetimi mekanizmalarıdır. Bu mekanizmalar, uygulamanızın performansını ve yanıt hızını önemli ölçüde artırır.

Query Cache ve Yapısı

QueryClient, tüm sorgu verilerini Query Cache adı verilen dahili bir yapıda saklar. Her sorgu, benzersiz bir anahtar (query key) ile tanımlanır ve bu anahtar altında ilgili veriler, meta veriler (stale durumu, son güncelleme zamanı vb.) depolanır. Bir sorgu anahtarı, genellikle bir dizi olarak tanımlanır ve sorgunun parametrelerini içerebilir: ['todos', { status: 'active' }].

Stale-While-Revalidate Prensibi

React Query'nin temelinde, HTTP cache'inden esinlenilmiş "stale-while-revalidate" prensibi yatar. Bu prensip, kullanıcılara anında önbelleğe alınmış (stale) veriyi gösterirken, arka planda bu veriyi güncelleyerek taze verinin hazır olmasını sağlar. Bu sayede kullanıcılar asla boş bir ekranla karşılaşmaz ve uygulamanız her zaman hızlı hissettirir.

Cache Süreleri (staleTime, cacheTime)

staleTime ve cacheTime, React Query'nin önbellekleme davranışını kontrol eden iki önemli ayardır:
* staleTime: Bir sorgunun ne kadar süre "taze" (fresh) kalacağını belirler. Bu süre boyunca, sorgu verisi önbellekten doğrudan döndürülür ve arka planda herhangi bir yeniden getirme (refetch) tetiklenmez. staleTime süresi dolduğunda, veri "stale" (bayat) hale gelir. Bir sorgu "stale" olduğunda ve yeniden render edildiğinde veya başka bir olay (pencereye odaklanma gibi) tetiklendiğinde, React Query arka planda veriyi yeniden getirmeye çalışır. Varsayılan olarak 0'dır, yani veri hemen "stale" olur.
* cacheTime: Bir sorgunun önbellekte ne kadar süre saklanacağını belirler. Bir sorgu artık aktif olarak kullanılmadığında (yani, ilgili tüm useQuery hook'ları unmount olduğunda), cacheTime geri saymaya başlar. Bu süre sonunda, veri önbellekten tamamen silinir (garbage collection). Varsayılan olarak 5 dakikadır.

Bu iki ayarın doğru kombinasyonu, uygulamanızın performansını ve bellek kullanımını optimize etmek için kritik öneme sahiptir.

QueryClient ile Etkileşim: Metotlar ve Kullanım Senaryoları

QueryClient örneği, önbelleği doğrudan manipüle etmek ve sorgularla etkileşim kurmak için çeşitli güçlü metotlar sunar. Bu metotlar, React Query'nin deklaratif doğasını tamamlayarak karmaşık senaryolarda esneklik sağlar.

queryClient.invalidateQueries(): Veriyi Geçersiz Kılma

Bu metot, belirli bir sorgu anahtarına (veya anahtar desenine) uyan tüm sorguları "stale" olarak işaretler ve aktif olanları yeniden getirir. Genellikle bir mutasyon (veri güncelleme, silme, oluşturma) başarılı olduğunda, ilgili sorguların önbelleğini geçersiz kılmak için kullanılır.

// Bir ürün güncellendikten sonra, tüm ürünler listesini ve ilgili ürün detayını geçersiz kıl
const mutation = useMutation({
  mutationFn: updateProduct,
  onSuccess: () => {
    queryClient.invalidateQueries({ queryKey: ['products'] }); // Tüm ürünleri geçersiz kıl
    queryClient.invalidateQueries({ queryKey: ['product', productId] }); // Belirli ürünü geçersiz kıl
  },
});


Bu, kullanıcıya her zaman en güncel veriyi sunmanın en yaygın ve etkili yoludur.

queryClient.setQueryData(): Cache'i Doğrudan Güncelleme

setQueryData, bir sorgunun önbelleğini doğrudan, API çağrısı yapmadan güncellemenizi sağlar. Bu, özellikle mutasyonlar sonrası iyimser güncellemeler (optimistic updates) yapmak veya sunucudan dönen yeni veriyi manuel olarak önbelleğe yazmak istediğinizde kullanışlıdır.

// Bir "todo" öğesini tamamladıktan sonra, listeyi API çağrısı yapmadan güncelle
const mutation = useMutation({
  mutationFn: completeTodo,
  onMutate: async (newTodo) => {
    // İyimser güncelleme için mevcut sorguyu iptal et
    await queryClient.cancelQueries({ queryKey: ['todos'] });

    // Mevcut veriyi al
    const previousTodos = queryClient.getQueryData(['todos']);

    // Cache'i iyimser bir şekilde güncelle
    queryClient.setQueryData(['todos'], old =>
      old ? old.map(todo => (todo.id === newTodo.id ? { ...todo, completed: true } : todo)) : []
    );

    return { previousTodos }; // Hata durumunda geri almak için
  },
  onError: (err, newTodo, context) => {
    // Hata durumunda cache'i eski haline getir
    queryClient.setQueryData(['todos'], context.previousTodos);
  },
  onSettled: () => {
    // Mutasyon tamamlandığında (başarılı veya başarısız), veriyi yeniden getir
    queryClient.invalidateQueries({ queryKey: ['todos'] });
  },
});

queryClient.getQueryData(): Cache'ten Veri Okuma

getQueryData, belirli bir sorgu anahtarına ait veriyi önbellekten senkronize olarak okumanızı sağlar. Bu metot, genellikle setQueryData ile birlikte iyimser güncellemeler yaparken veya uygulamanızın başka bir yerinde önbellekteki veriye erişmeniz gerektiğinde kullanılır.

const todos = queryClient.getQueryData(['todos']);
if (todos) {
  console.log("Önbellekteki todos:", todos);
}

queryClient.prefetchQuery(): Veri Önceden Yükleme

prefetchQuery, bir sorguyu kullanıcıya gösterilmeden önce arka planda önbelleğe yüklemek için kullanılır. Bu, kullanıcı bir sayfaya veya bileşene tıkladığında verinin zaten hazır olmasını sağlayarak yükleme sürelerini önemli ölçüde azaltır.

// Bir linkin üzerine gelindiğinde (hover), ilgili sayfanın verisini önceden yükle
const handleMouseEnter = () => {
  queryClient.prefetchQuery({
    queryKey: ['post', 1],
    queryFn: () => fetch('/api/posts/1').then(res => res.json()),
  });
};


  Post 1'e Git

Optimizasyon ve Performans İpuçları

QueryClient'ı doğru bir şekilde yapılandırmak ve kullanmak, React uygulamanızın performansını maksimize etmenin anahtarıdır.

staleTime ve cacheTime Ayarlarının Doğru Kullanımı

Bu iki ayar arasındaki dengeyi bulmak çok önemlidir:
* Yüksek staleTime: Nadiren değişen veriler için (örneğin, statik konfigürasyonlar, kullanıcı profili bilgileri) yüksek staleTime ayarlamak, gereksiz API çağrılarını önler ve performansı artırır.
* Düşük staleTime: Sık sık değişen veriler için (örneğin, sohbet mesajları, borsa verileri) düşük staleTime veya varsayılan 0 kullanmak, kullanıcıya her zaman en güncel veriyi sunmayı garantiler.
* Yüksek cacheTime: Kullanıcının sık sık ziyaret ettiği ancak aktif olarak kullanılmayan sayfaların verilerini önbellekte tutmak için yüksek cacheTime kullanabilirsiniz.
* Düşük cacheTime: Bellek kullanımını azaltmak için nadiren erişilen veya çok büyük veriler için düşük cacheTime ayarlayabilirsiniz.

Garbage Collection ve Bellek Yönetimi

cacheTime ayarı, QueryClient'ın dahili çöp toplama (garbage collection) mekanizmasını tetikler. Bir sorgu cacheTime süresi boyunca kullanılmazsa, önbellekten silinir. Bu, özellikle mobil cihazlarda veya çok sayıda farklı veri sorgusu olan uygulamalarda bellek ayak izini yönetmek için önemlidir. Kullanılmayan verilerin önbellekte süresiz kalmasını engeller.

select Fonksiyonu ile Veri Dönüşümü

useQuery hook'unun select seçeneği, sorgudan dönen veriyi doğrudan QueryClient'ın önbelleğine yazılmadan önce dönüştürmenize olanak tanır. Bu, gereksiz yeniden render'ları önleyerek performansı artırabilir, çünkü sadece dönüştürülmüş veri değiştiğinde bileşen yeniden render edilir.

const { data: userNames } = useQuery({
  queryKey: ['users'],
  queryFn: fetchUsers,
  select: (users) => users.map(user => user.name), // Sadece isimleri al
});
// userNames sadece isimlerden oluşan bir dizi olacaktır.

QueryClient'ın Gelişmiş Kullanım Alanları

QueryClient'ın temel yeteneklerinin ötesinde, daha karmaşık ve güçlü kullanım senaryoları da mevcuttur.

Mutasyon Sonrası Cache Güncelleme (onSuccess, onError)

useMutation hook'unun onSuccess ve onError callback'leri, bir mutasyon tamamlandıktan sonra QueryClient metotlarını kullanarak önbelleği akıllıca güncellemek için ideal yerlerdir. onSuccess içinde invalidateQueries veya setQueryData kullanarak, sunucudan dönen yeni veriye göre önbelleği güncelleyebiliriz. onError içinde ise iyimser güncellemeleri geri almak için setQueryData kullanılabilir.

const mutation = useMutation({
  mutationFn: addTodo,
  onSuccess: (newTodo) => {
    // Yeni eklenen todo'yu doğrudan cache'e ekleyebiliriz
    queryClient.setQueryData(['todos'], (oldTodos) => [...oldTodos, newTodo]);
    // Veya sadece 'todos' sorgusunu geçersiz kılarak yeniden getirmesini sağlayabiliriz
    // queryClient.invalidateQueries({ queryKey: ['todos'] });
  },
  onError: (error, variables, context) => {
    // Hata durumunda iyimser güncellemeyi geri al
    // context içinde onMutate'ten dönen veriler olabilir
  },
});

Offline Senaryolar ve Retry Mekanizmaları

QueryClient, ağ bağlantısı kesildiğinde sorguları otomatik olarak yeniden denemek için dahili bir retry mekanizmasına sahiptir. defaultOptions içinde veya her bir useQuery çağrısında retry sayısını ve retryDelay'i yapılandırabilirsiniz. Bu, uygulamanızın çevrimdışı durumdan çevrimiçi duruma geçtiğinde otomatik olarak kendini iyileştirmesine yardımcı olur.

const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      retry: 5, // 5 kez yeniden dene
      retryDelay: attemptIndex => Math.min(1000 * (2 ** attemptIndex), 30000), // Üstel geri çekilme
    },
  },
});

Custom QueryClient Hook'ları

Uygulamanızda sıkça kullanılan belirli QueryClient etkileşimleri varsa, bunları kendi özel hook'larınız (custom hooks) içine kapsülleyebilirsiniz. Bu, kod tekrarını azaltır, okunabilirliği artırır ve iş mantığını bileşenlerden ayırır.

// useInvalidateTodos.js
import { useQueryClient } from '@tanstack/react-query';

export function useInvalidateTodos() {
  const queryClient = useQueryClient();
  return () => queryClient.invalidateQueries({ queryKey: ['todos'] });
}

// Bir bileşende kullanımı
import { useInvalidateTodos } from './useInvalidateTodos';

function TodoList() {
  const invalidateTodos = useInvalidateTodos();

  const mutation = useMutation({
    mutationFn: deleteTodo,
    onSuccess: () => {
      invalidateTodos(); // Kendi hook'umuzu kullanıyoruz
    },
  });

  // ...
}

Sonuç

QueryClient, React Query'nin kalbinde yer alan, uygulamanızın veri yönetimini basitleştiren ve performansını artıran temel bir yapıdır. Onun yeteneklerini ve metotlarını derinlemesine anlamak, daha verimli, sürdürülebilir ve kullanıcı dostu React uygulamaları geliştirmenizi sağlar. QueryClient'ın sunduğu önbellekleme, senkronizasyon ve etkileşim mekanizmalarını ustaca kullanarak, veri katmanınızın karmaşıklığını soyutlayabilir ve geliştirme sürecinizi hızlandırabilirsiniz. React Query ile çalışırken, QueryClient'ın gücünü tam olarak kullanmaktan çekinmeyin; uygulamanız size teşekkür edecektir.

SSS (Sık Sorulan Sorular)

QueryClient nedir ve neden React Query'de kullanılır?

QueryClient, React Query'nin tüm veri yönetimini, önbellekleme mekanizmalarını, arka plan güncellemelerini ve hata yönetimini merkezi olarak kontrol eden ana nesnesidir. Uygulamanızdaki veri akışını otomatikleştirerek geliştiricilerin manuel önbellekleme ve veri senkronizasyonu gibi karmaşık görevlerden kurtulmasını sağlar.

staleTime ve cacheTime arasındaki temel fark nedir?

staleTime, bir sorgunun ne kadar süre "taze" kalacağını belirler. Bu süre dolduğunda sorgu "bayat" (stale) hale gelir ve bir sonraki kullanımda arka planda yeniden getirilebilir. cacheTime ise bir sorgunun önbellekte ne kadar süre saklanacağını belirler. Sorgu aktif olarak kullanılmadığında bu süre başlar ve dolduğunda veri önbellekten tamamen silinir (garbage collection).

queryClient.invalidateQueries() ne zaman kullanılmalıdır?

invalidateQueries() genellikle bir mutasyon (veri oluşturma, güncelleme, silme) başarılı olduğunda, ilgili sorguların önbelleğini geçersiz kılmak ve böylece bu sorguların bir sonraki kullanımda en güncel veriyi API'den çekmesini sağlamak için kullanılır.

Birden fazla QueryClient kullanmak mümkün müdür?

Evet, mümkündür. QueryClientProvider'ı farklı QueryClient örnekleriyle sarmalayarak uygulamanızın farklı bölümleri için ayrı önbellekler ve yapılandırmalar kullanabilirsiniz. Ancak çoğu durumda tek bir QueryClient yeterli olacaktır.

QueryClient, React Server Components (RSC) veya SSR ile nasıl çalışır?

React Query, hem SSR (Server-Side Rendering) hem de RSC (React Server Components) ile uyumludur. SSR ortamında, sunucuda bir QueryClient örneği oluşturulur, sorgular sunucuda önceden getirilir ve önbellek verisi istemciye hidrasyon (hydration) için aktarılır. Bu, kullanıcının ilk yüklemede dolu bir içerik görmesini sağlar. RSC'ler için de benzer bir yaklaşım izlenir, sunucu bileşenleri kendi veri getirme mantıklarını QueryClient ile entegre edebilir.

Yorumlar
İçeriği beğendiniz mi? Bir tartışma başlatın veya görüşlerinizi paylaşın.
Yorum Yaz

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

Gönder

E-posta Bülteni
Yazılım Topluluğuna Katılın
En son güncellemeleri, yaratıcı ipuçlarını ve özel kaynakları doğrudan e-posta kutunuza alın. Tasarım ve inovasyonun geleceğini birlikte keşfedelim.
Mobil sürümden çık