Sign in
Log inSign up
React Query Nedir? Nasıl Kullanılır?

React Query Nedir? Nasıl Kullanılır?

Şamil Kahraman's photo
Şamil Kahraman
·Dec 18, 2021·

5 min read

React Query, React uygulamalarında veri getirme işlemlerini, gelen verinin önbelleğe alınmasını, senkronize edilmesini ve eskiyen verinin güncellenmesini kolaylaştıran bir kütüphanedir.

Vermiş olduğum örneklerin altına codesandbox örneği ekledim. Dolayısıyla yazıdaki kod örneklerinde kütüphane importlarını kalabalık olmaması için haricen eklemedim.

Öne çıkan özellikleri:

  • Önbellekleme (sunucudan defalarca aynı veriyi çağırmanın önüne geçme)
  • Verinin belli periyotlarla güncellenmesi, bu sürenin ayarlanması ve değişikliklerin hızlıca yansıtılması
  • Verinin sayfa sayfa çağrılması veya lazy loading gibi işlemlerde performans optimizasyonu
  • Server durumundaki bellek yönetimi ve garbage collection işlemlerinin yönetilmesi.

Bu noktadaki şahsi yorumlarından biri de React Query kütüphanesi kodun okunabilirliğini artırmakta ve asenkron verilerle çalışma stratejisini standartlaştırmaktadır.

Standart yöntem ile API çağrısı ve React query ile api çağrısı örneğini inceleyelim ve adım adım ekleme yapalım.

Klasik API Çağrı Örneği

// Standart çağrı örneği
function Classic() {
  const [data, setData] = useState({});
  const [error, setError] = useState();
  const [isLoading, setIsLoading] = useState(true);
  useEffect(() => {
    const fetchData = async () => {
      try {
        const response = await fetch(
          "api.github.com/repos/samilkahraman/m220"
        );
        const json = await response.json();
        setIsLoading(false);
        setData(json);
      } catch (err) {
        setError(err);
      }
    };
    fetchData();
  }, []);

  if (isLoading) return "Yükleniyor...";

  if (error) return "Hata meydana geldi: " + error.message;

  return (
    <div>
      <h1>{data.name}</h1>
      <p>{data.full_name}</p>
      <strong>👀 {data.visibility}</strong>{" "}
    </div>
  );
}

Standart bir asenkron API çağrı örneği yaptık. Burada görüldüğü üzere hataları kendimiz yakalamalıyız ve yüklenme bilgisi için haricen bir durum yönetmeliyiz.

Bu yöntemi bir çok çağrı ile çalışan bir sistemde düzgün ve sistematik yönetmek bir süre sonra çok uzun zaman alıp yıldırıcı bir hale gelebilir.

Şimdi ise React Query ile aynı örneğe bakalım.

React Query API Çağrı Örneği

function ReactQueryExample() {
  const { isLoading, error, data } = useQuery("repoData", () =>
    fetch("api.github.com/repos/samilkahraman/m220").then((res) =>
      res.json()
    )
  );

  if (isLoading) return "Yükleniyor...";

  if (error) return "Hata meydana geldi: " + error.message;

  return (
    <div>
      <h1>{data.name}</h1>
      <p>{data.full_name}</p>
      <strong>👀 {data.visibility}</strong>{" "}
    </div>
  );
}

Görüldüğü üzere React Query kütüphanesi asenkron çağrıları kendi içerisinde yapmakta ve kod kalabalığından kurtarırken aynı şekilde sunucu durumunu kendisi kontrol etmektedir.

Kod örneği: Codesandbox

Şimdi asıl özelliklere gelebiliriz.

React Query Önbellek İşlemleri

useQuery veya useInfiniteQuery ile yapılan sorgular otomatik olarak eski/bayat(stale) olarak önbelleklenir.

Eski/Bayat sorgular aşağıdaki koşullarda otomatik olarak tekrar çağrılır.

  • Tarayıcı penceresine yeniden gelindiğinde.
  • İnternet bağlantısı yeniden sağlandığında
  • Opsiyonel olarak belli aralıklarla çağrılması sağlandıysa

Örneğin sorgunun bayatlama/eskime süresini aşağıdaki gibi ayarlayabiliriz.

const second = 1000;
const minute = 60 * second;
const twoMinutes = 2 * minute;
const { isLoading, error, data } = useQuery("ornekCagri", () =>
    fetch("api.github.com/repos/samilkahraman/m220").then((res) =>
      res.json()
    ), {staleTime:twoMinutes}
  );

Eklemiş olduğumuz {staleTime:twoMinutes} parametresiyle artık her 2 dakikada bir otomatik olarak verimiz çağrılacaktır. Bu şekilde verinin güncelliğiyle ilgili kaygıya gerek kalmayacaktır.

Bu parametre konulmadan önceki ve sonraki verinin "ReactQueryDevtools" ile görünümüne bakalım.

Öncelikli olarak staleTime belirtmeyince ne oluyor.

bayat-react-query.png

Şimdi ise {staleTime:twoMinutes} parametresini verdiğimizde ne olduğuna bakalım.

iki-dakika-react-query-stale.png

Görüldüğü üzere verinin güncelliğini staleTime parametresiyle kontrol edebiliyoruz. Bu kontrol işlemi standart yöntemlerle oldukça meşakkatli olacaktı.

Tekrar önbelleğe dönersek bu sorgu yapıldığı an itibariyle önbelleğe alınıyor ve uygulama içi farklı sayfalara geçtiğimizde React Query eski sorguları inactive olarak işaretliyor. Inactive sorgular default olarak 5 dakika sonra React Query Garbage Collector tarafından ön bellekten temizleniyor. Bu davranışı cacheTime parametresiyle birlikte uzatabilirsiniz.

Bu noktadan itibaren resmi dökümantasyon üzerindeki sıra ile hızlı bir özet yapmaya çalışacağım.

React Query Sorgu Yapıları

Kütüphaneyi kullanırken GET Talepleri için useQuery kullanılırken POST taleplerinde useMutation kullanılması önerilmektedir. Bu bağlamda yalnıza useQuery üzerinden anlatıma devam edeceğim fakat yazının ilerleyen bölümlerinde haricen useMutation kısmına değineceğim.

useQuery ile işlem yapılırken iki önemli parametre kullanılıyor:

const result = useQuery('uniqueKey', fetchData)
  • Uniqe Key. Her bir sorgunuz eşsiz(unique) bir anahtar(key) ile yapılmalıdır. Eşsiz anahtarla birlikte aynı sorguyu kodunuzun farklı yerlerinden yönetme imkanı bulmaktasınız.
  • Promise dönen fonksiyon Fonksiyon promise resolve etmeli ya da error throw etmelidir.

useQuery sonucunda result objesi aşağıdaki durumları içermektedir.

  • isLoading (Sorguda data yok fakat aktif bağlantıda yükleniyor)
  • isError (Sorgu hata ile karşılaştı)
  • isSuccess (Sorgu başarılı ve dataya erişilebilir)

Sorgu Anahtarları

Sorgularda eşsiz anahtar kullanılması gerektiğinden bahsettik fakat bu yöntemi uygulamamız belirli durumlarda zor olacaktır. Örneğin aşağıdaki tabloda görüldüğü gibi api/chat/:id şeklinde bir uç noktadan bütün aktif mesajları tek bir tabloya çağırdığımızı düşünelim.

Ekran Resmi 2021-12-18 16.01.46.png

Burada data grid hücreleri içerisinde her bir projeye ait son chat mesajını getiriyoruz, fakat bunların her birini isimlendirmek için aynı key'i kullanamayız çünkü anahtarlar eşsiz olmalıdır. Burada imdadımıza React Query array ile isimlendirme yetişiyor.

useQuery(['fetchChatMessages', id], ...)

Yani sorgulardaki isimleri doğrudan string değil de array ile atayarak sorgulama yapıyoruz.

Ekran Resmi 2021-12-18 16.11.14.png

Görüldüğü gibi projeler tek bir sorgu ile gelirken, projelerin mesajları ayrı sorgularla ulaşılabilir konumda olduğundan aynı eşsiz anahtara ID eklenerek sorgulama yapılıyor.

React Query Paralel Sorgular

Bir sayfada birden fazla kaynağın yüklendiği bir çok senaryo mevcut. Bu durumlarda React Query'yi paralel olarak kullanmanızda bir problem olmamakta.

 const usersQuery = useQuery('users', fetchUsers)
 const teamsQuery = useQuery('teams', fetchTeams)
 const projectsQuery = useQuery('projects', fetchProjects)

Fakat burada dikkat edilmesi gereken yazının başındaki örnekteki gibi isLoading, data, error durumlarını doğrudan çıkartamadık.

const { isLoading, error, data } = useQuery('projects', fetchProjects)

Fakat halen objenin parametrelerine ulaşabildiğimiz için farklı yöntemlerle benzer şekilde kullanabiliriz.

const fetchUsers = () =>
  fetch("api.github.com/repos/samilkahraman/m220").then((res) =>
    res.json()
  );
// Hata dönmesi için özellikle github yerine gihub yazıldı
const fetchTeams = () =>
  fetch("api.gihub.com/repos/samilkahraman/m220").then((res) =>
    res.json()
  );
const fetchProjects = () =>
  fetch("api.github.com/repos/samilkahraman/m220").then((res) =>
    res.json()
  );

function ReactParallelQueryExample() {
  const usersQuery = useQuery("users", fetchUsers);
  const teamsQuery = useQuery("teams", fetchTeams);
  const projectsQuery = useQuery("projects", fetchProjects);

  const { isLoading, error, data } = useQuery("ornekCagri", () =>
    fetch("api.github.com/repos/samilkahraman/m220").then((res) =>
      res.json()
    )
  );

  if (isLoading) return "Yükleniyor...";

  if (error) return "Hata meydana geldi: " + error.message;

  return (
    <>
      <div>
        Kullanıcı Sorgusu Durumu: {conditionalColoring(usersQuery.status)}
      </div>
      <div>
        Takımlar Sorgusu Durumu: {conditionalColoring(teamsQuery.status)}
      </div>
      <div>
        Projeler Sorgusu Durumu: {conditionalColoring(projectsQuery.status)}
      </div>

      <p>{data.full_name}</p>
    </>
  );
}

const conditionalColoring = (status) =>
  status === "success" ? <>🟢 success</> : <>🔴 error</>;

image.png

Codesandbox

React Query Bağımlı Sorgular

Eğer sorgunun yapılabilmesi kendisinden önceki sorgulara bağlı ise sadece bir parametre ile bunu sağlayabilirsiniz. { enabled:false }

 // Kullanıcıyı getir
 const { data: user } = useQuery(['user', email], getUserByEmail)

 const userId = user?.id

 // Kullanıcının projesini getir
 const { isIdle, data: projects } = useQuery(
   ['projects', userId],
   getProjectsByUser,
   {
     // Kullanıcı ID'si gelene kadar sorgu çalışmayacaktır.
     enabled: !!userId,
   }
 )

Birinci bölüm sonu

Buraya kadar olan kısım React Query giriş seviyesi için yeterli olduğunu düşündüğümden yazının daha fazla ilerlememesi için sonlandıracağım. Bir sonraki bölümde bir adım ilerisinde neler yapılabileceğini aynı şekilde anlatmaya çalışacağım. Umarım merak edenlere faydalı olur.