React Native Uygulamalarında RTK Query Kullanımı

F.Zehra Güneş
HangiKredi
Published in
5 min readSep 25, 2024

Uygulamaların yüzlerce servis ile bütünleşik çalıştığı geliştirme ortamlarında verinin yönetimi, bütünlüğü ve güncelliği kritik önem taşıyor. HangiKredi mobil uygulaması geliştirme süreçlerinde veri çekme, verinin yönetimi ve otomatik cachelenmesini sağlayan RTK Query kullanılmaktadır. Güncel veri döngüsünü ve yönetimini basitleştiren, uygulama performansını arttıran RTK Query’nin proje içerisindeki kullanım alanlarına, performansa katkısına ve kolaylaşan geliştirme sürecine değineceğim. Özellikle çoklu API entegrasyonlarında yaşanabilecek veri tutarsızlığı ve gereksiz network istekleri sorunlarını çözmek için RTK Query güçlü bir çözüm olmaktadır.

Redux Toolkit Query Nedir?

RTK Query, bir çok API requestinde tekrar tekrar yazmamız gereken durumları ortadan kaldıran ve veri çekme ve auto-caching işlemlerini performanslı ve basitleştirilmiş şekilde yönetmemizi sağlayan güçlü bir araç. Redux Toolkit ekosisteminin bir parçası olan RTK Query, opsiyonel olarak sunulur ve Toolkit’in createSlice ve createAsyncThunk API’leri üzerine inşa edilmiştir. Redux Toolkit state yönetimi için kullanılırken, RTK Query özellikle veri çekme ve caching için özelleştirilmiş bir çözüm sunmakta. Mevcut Redux kullanan React Native projelerine de kolayca entegre edilebilir.

  • Verileri otomatik olarak önbelleğe alır ve yönetir.
  • Oluşturulan hook ile isFetching, isSuccess, error gibi stateleri otomatik olarak yönetir.
  • Aynı endpoint için yinelenen istekleri engeller.
  • TypeScript desteği debugging süreçlerini iyileştirir ve kod kalitesini arttırır.
  • Uygulama UI’ı API yanıtı beklenmeden güncellenir, bu sayede kullanıcı deneyimini iyileştirir.
  • Redux ile karşılaştırıldığında daha az boilerplate kod ve daha temiz bir yapı sağlar.

Data Fetching Mekanizması

API istekleri için proje içerisinde merkezi bir yerde RTK Query’nin temel fonksiyonu olan createApi() içerisine ilgili endpoint(ler) tanımlanır, bu kodun temiz ve tutarlı bir yapıda veri çekme işlemlerini barındırmasını sağlar.

  • Endpointler Query veya Mutation olabilir. Query sadece veri almak için kullanılırken veri güncelleme, silme veya ekleme işlemleri için mutation kullanılır. Önbelleği etkileyen işlemler içinse mutation kullanılır. Aşağıda cache kısmında bunu örneklendirdim. Örnek bir api dosyası ise şuna benzemekte;
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react';

export const api = createApi({
baseQuery: fetchBaseQuery({ baseUrl: 'https://api.hangikredi.com/' }),
endpoints: (builder) => ({
// Ürünleri listeleyen query
getProducts: builder.query<Product[], void>({
query: () => 'products',
}),
}),
});

// Otomatik olarak oluşan hook export edilir
export const { useGetProductsQuery} = productApi;
  • Tanımlanan her endpoint için endpoint ile aynı isimde hook oluşur. Her endpoint için farklı modda hooklar (useQuery veya useLazyQuery) çıkarılabilir. Bu sayede aynı endpointin tekrar tekrar çağrılması durumu ortadan kalkmış olur.
  • Hook api dosyasından export edilerek kullanılabilir hale gelir, ekran(lar)ın render edilmesi esnasında API isteği yapılması için useQuery modundaki hook çağrılır. Ekran render edildikten sonraki bir zamanda form doldurma veya butona basma gibi bir koşula bağlı olarak api isteği yapılacaksa useLazyQuery hook’u içerisindeki trigger function ile Api istekleri yapılır.
import React, { useCallback } from 'react';
import { View, Text, Button} from 'react-native';
import { useGetSomeProductsQuery, useLazyGetOtherProductsQuery } from './api'; // api'den doğru import edin

const ProductScreen = () => {

// useQuery hook'u ile otomatik veri çekme
const { data, isLoading: isLoadingSome } = useGetSomeProductsQuery();

// useLazyQuery hook'u ile trigger fonksiyonunun çağrıldığı yerde query çalışır
const [getOtherData, { otherData, isLoading: isLoadingOther }] = useLazyGetOtherProductsQuery(getProducts);

const onPressTrigger = useCallback(() => {
getData()
.unwrap()
.then(product => {
if (product) {
console.log(product);
}
});
}
}, [getData]);

if (isLoadingSome || isLoadingOther) return <Text>Loading...</Text>;

return (
<View>
<Text>Otomatik Veriler:</Text>
{data && data.map(product => (
<Text key={product.id}>{product.name}</Text>
))}
<Text>Diğer Veriler:</Text>
{otherData && otherData.map(product => (
<Text key={product.id}>{product.name}</Text>
))}
<Button onPress={onPressTrigger} title="Diğer Verileri Yükle" />
</View>
)
  • Query hookları React bileşenlerinin yaşam döngüsüne entegre çalışır. Bileşen mount olduğunda otomatik olarak veriyi çeker. Manuel olarak useEffect gibi hooklarla yükleme/hata durumunu veya bağımlılıkları yönetmeye gerek kalmaz.
  • Hooklar return objesi içinde isFetching, isLoading gibi response’u takip ettiğimiz stateleri ve varsa response datayı döner. Bu sayede UI görünümü çok daha temiz bir kod yapısı ile yönetilir. Aşağıda iki kullanım arasındaki kod yapısındaki farkı örneklendirdim.
// RTK Query ile useQuery kullanımı
import { useGetUserQuery } from './api';

function UserComponent({ userId }) {
const { data, isLoading, isError, error } = useGetUserQuery(userId);

if (isLoading) return <Text>Loading...</Text>;
if (isError) return <Text>Error: {error.message}</Text>;

return <Text>{data.name}</Text>;
}

// Normal API fonksiyonu kullanımı
import { useState, useEffect } from 'react';
import axios from 'axios';

function UserComponent({ userId }) {
const [data, setData] = useState(null);
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState(null);

useEffect(() => {
const fetchUser = async () => {
try {
setIsLoading(true);
const response = await axios.get(`/api/users/${userId}`);
setData(response.data);
} catch (err) {
setError(err);
} finally {
setIsLoading(false);
}
};

fetchUser();
}, [userId]);

if (isLoading) return <Text>Loading...</Text>;
if (error) return <Text>Error: {error.message}</Text>;

return <Text>{data?.name}</Text>;
}
  • Pagination’ı desteklemektedir, listelemelerde infinite scrolling istediğimizde kullanışlıdır.
  • Parallel Query mantığında çalışan RTK Query aynı anda birden fazla API çağrısını eşzamanlı olarak yapabilmekte. Aynı ekranda birden fazla query hook’u ile veri almak istediğimizde kullanışlıdır.
const { data: products } = useGetProductsQuery();
const { data: userFavorites } = useGetUserFavoritesQuery();

Cache Yönetimi

  • RTK Query ile API yanıtları herhangi ek bir tanıma ihtiyaç duymaksızın Redux store’da cachelenir. Aynı veriye tekrar tekrar erişilmesi gereken durumlarda cache verisi kullanılır, uygulamadaki gereksiz network isteklerini ve server üzerindeki yük azaltılır, uygulamanın performansını arttırır.
  • Cache’in geçersiz kılınarak yenilenmesi(auto-fetching olarak da adlandırılır) taglerle yönetilir. Örneğin kullanıcının favorilerini ‘UserFavorites’ tag’i ile store’a provide ettiysek daha sonra gerçekleşecek bir mutation-favorileri değiştirmek gibi- ile ‘UserFavorites’ tag’i ile tanımlanmış tüm cache verisi invalidate edilebilecek ve verilerin update edilmesi için ilgili endpointlere istek yapılacaktır. Bu tag tanımlamaları yapılarak ve tekrar veri çekme işlemleri otomatize edilerek uygulama içerisinde veriler her zaman en güncel versiyonunda gösterilir.
  • Verileri cache’te tutmak istediğimiz bazı durumlar olabilir, bunun keepUnusedDataFor parametresi düzenlenir. Varsayılanda 60 saniyedir, API tanımında veya endpoint bazında özelleştirilebilir.
  • Cache invalidation kurgusunu aşağıda örneklendirdim.
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react';

export const api = createApi({
baseQuery: fetchBaseQuery({ baseUrl: 'https://api.hangikredi.com' }),
tagTypes: ['UserFavorites'],
endpoints: (builder) => ({
getUserFavorites: builder.query<Favorite[], void>({
query: () => 'favorites',
providesTags: ['UserFavorites'],
}),
updateUserFavorite: builder.mutation<FavoriteResponse, FavoriteRequest>({
query: (favorite) => ({
url: `favorites/${favorite.id}`,
method: 'PATCH',
body: favorite,
}),
invalidatesTags: ['UserFavorites'],
}),
}),
});

export const { useGetUserFavoritesQuery, useUpdateUserFavoriteMutation } = api;

RTK Query’nin API isteklerinin kapsamlı olduğu bir projede karşıladığı ihtiyaçlar ve sağladığı faydalar konsept olarak bu şekilde özetlenebilir.

--

--