React uygulamasında Apollo Client ile GraphQL verisi çekmek ve güncellemek
Apollo Client ile GraphQL istemcisi kurulumu: ApolloClient ve önbellek, useQuery ile veri çekme, useMutation ile güncelleme, önbellek yönetimi ve hata ele alma.
Apollo Client ne yapar, ne zaman gerekir?
Apollo Client, bir GraphQL sunucusuyla konuşan React uygulamaları için durum yönetimi ve veri çekme kütüphanesidir. Sorguyu gönderir, sonucu bir önbellekte tutar, yükleniyor ve hata durumlarını bileşene verir, veri değişince arayüzü günceller. Aynı işi fetch ve elle yazılmış bir durum yapısıyla yapmak mümkündür, ama aynı verinin birden fazla ekranda tutarlı kalması, tekrarlanan isteklerin önlenmesi ve yükleme hatalarının yönetimi her projede yeniden yazılmak zorunda kalır.
Apollo Client'ı şu durumlarda tercih edin: API zaten GraphQL ise, birçok ekran aynı nesneleri farklı alanlarla gösteriyorsa, önbellek tutarlılığı ve iyimser (optimistic) güncelleme istiyorsanız. Küçük bir REST tabanlı uygulamada gereksiz ağırlık olabilir. İstemci tarafı, sunucu tarafından ayrı bir beceridir; sunucu yazımı ve şema tasarımı için ilgili sayfalara bakın.
Kurulum: istemci, önbellek ve Provider
Kurulum için şu paketler gerekir: @apollo/client, graphql ve rxjs. Ardından istemci bir kez oluşturulur ve uygulama onunla sarılır. Resmî başlangıç rehberindeki yapı şöyledir:
- İstemci oluşturma: ApolloClient sınıfına bir bağlantı (HttpLink ile uri) ve bir önbellek (InMemoryCache) verilir.
- Provider: uygulamanın en üstünde ApolloProvider, istemciyi client özelliği olarak alır; böylece alttaki tüm bileşenler hook'lara erişir.
Örnek iskelet:
const client = new ApolloClient({ link: new HttpLink({ uri: GRAPHQL_ADRESI }), cache: new InMemoryCache() });
root.render(<ApolloProvider client={client}><App /></ApolloProvider>);
Bu yapının yanında ortam değişkeniyle API adresini yönetmek ve kimlik doğrulama başlığını istemciye eklemek üretimde gereken ilk adımlardır. Hook'ların hangi paket yolundan içe aktarıldığı sürüme göre değişebildiği için kullandığınız sürümün belgesini izleyin; son rehberde hook'lar @apollo/client/react yolundan alınmaktadır.
useQuery ile veri çekme
Sorgu, gql işleviyle tanımlanır ve useQuery hook'una verilir. Hook, bileşen çizildiğinde isteği başlatır ve loading, error, data alanlarını döndürür.
Örnek:
const GET_LOCATIONS = gql(SORGU_METNI); // SORGU_METNI: query GetLocations { locations { id name description photo } }
function DisplayLocations() { const { loading, error, data } = useQuery(GET_LOCATIONS); if (loading) return <p>Yükleniyor...</p>; if (error) return <p>Hata: {error.message}</p>; return data.locations.map(({ id, name }) => <b key={id}>{name}</b>); }
İyi uygulamalar:
- Sorguya yalnızca ekranın gerçekten kullandığı alanları yazın; GraphQL'in avantajı fazla veri çekmemektir.
- Her nesne için id (ya da _id) alanını isteyin; önbellek nesneleri bununla tanır.
- Parametreli sorgularda değişkenleri variables ile geçin, string birleştirme yapmayın.
- Yükleniyor, boş ve hata durumlarını baştan tasarlayın; çoğu üretim sorunu bu üç durumun unutulmasından çıkar.
- Sorguları bileşen dosyasının yanında ya da ayrı bir sorgu dosyasında toplayın ve isimlendirmeyi tutarlı tutun; isim, hata ayıklama ve yeniden getirme için de gerekir.
useMutation ve önbelleği güncel tutmak
Değişiklik işlemleri useMutation ile yapılır. Hook, bileşen çizilirken çalışmaz; döndürdüğü işlevi bir kullanıcı eylemiyle çağırırsınız ve değişkenleri geçirirsiniz:
const [addTodo, { data, loading, error }] = useMutation(ADD_TODO); addTodo({ variables: { type: deger } });
Mutasyondan sonra ekrandaki listelerin güncellenmesi için şu yollar vardır:
- refetchQueries: etkilenen sorguları yeniden çekmek. Sorgu belgesi, sorgu adı ya da etkin sorguların tümü için ayrı seçenekler vardır. En basit yoldur ama ek ağ isteği harcar.
- update işlevi: mutasyon sonucunu önbelleğe elle yazmak. cache.modify ile ilgili alanın listesine yeni nesne referansı eklenir; ağ isteği gerekmez.
- optimisticResponse: sunucudan yanıt gelmeden arayüzü sonucun tahminiyle güncellemek. Bu durumda update işlevi iki kez çalışır: önce tahmin, sonra gerçek sonuçla.
Sık hata: mutasyon sonucu sunucudan id döndürmüyorsa önbellek nesneyi mevcut kayıtla eşleştiremez ve ekran eski veriyi gösterir. Mutasyon yanıtına değişen nesnenin id ve güncellenen alanlarını mutlaka ekleyin.
Önbellek nasıl çalışır?
InMemoryCache, sorgu sonuçlarını düz bir nesne tablosu olarak saklar. Bir nesnenin önbellek kimliği varsayılan olarak __typename ve id alanlarının birleşimidir, örneğin Person:cGVvcGxlOjE gibi. İç içe nesneler, bu kimliklere işaret eden referanslarla değiştirilir; böylece aynı kişi iki farklı sorguda görünüyorsa tek bir kayıtta tutulur ve biri güncellenince ikisi de güncel olur.
Bunun pratik sonuçları:
- id alanı olmayan nesneler normalleştirilemez, üst nesnenin içinde kalır ve ayrı güncellenemez.
- Sorgu yanıtında __typename Apollo tarafından otomatik eklenir; elle yazmaya gerek yoktur.
- Bir nesne daha önce önbelleğe alınmışsa varsayılan davranış sunucuya gitmeden önbellekten dönmektir. Güncel veri şart olan ekranlarda sorgunun çekme politikasını (fetch policy) belgeye bakarak ayarlayın.
- Kimlik biçimi farklı bir tür için (örneğin id yerine kod alanı kullanan tür) önbellek kimliğini özelleştirmek gerekir; bunun için kullandığınız sürümün önbellek belgesindeki özelleştirme bölümüne bakın.
Apollo Client Devtools eklentisi önbellek içeriğini ve etkin sorguları görmeyi sağlar; önbellek sorunlarında ilk bakılacak yerdir.
Hata yönetimi
Apollo iki tür hatayı ayırır. GraphQL hataları sunucu işlemi yürütürken oluşur: sözdizimi, doğrulama ve çözümleyici (resolver) hataları. Yanıtın errors dizisinde gelir ve bazen kısmi veriyle birlikte olabilir. Ağ hataları ise isteğin normal tamamlanmamasıdır: sunucu hata durum kodu, erişilemeyen sunucu, geçersiz JSON gibi.
Hook sonucundaki error alanı ikisini de taşır; ayırmak için hata türüne bakılır (CombinedGraphQLErrors için .is denetimi). errorPolicy ayarı, kısmi veri geldiğinde ne olacağını belirler:
- none (varsayılan): hata döner, data tanımsız kalır.
- ignore: hata gizlenir, gelen veri önbelleğe yazılır ve normal çizilir.
- all: hem veri hem hata doldurulur; kısmi sonuç ile hata mesajı birlikte gösterilebilir.
Kullanıcıya gösterilen mesajı sunucu iç hata ayrıntısıyla karıştırmayın; kullanıcı dostu mesaj üretip ayrıntıyı günlüğe yazın. Oturum süresi dolduğunda gelen kimlik doğrulama hatası için bağlantı katmanında (link) merkezi bir yakalama kurmak, her bileşende ayrı kontrolden daha sağlamdır.
Mindset programında bu beceri
Apollo GraphQL ile İstemci ve Sunucu Geliştirme eğitimi, GraphQL temellerinden ve şema tasarımından Apollo Server ile sunucu geliştirmeye, Apollo Client ile istemci geliştirmeye, aboneliklere ve gerçek zamanlı veriye, performans, güvenlik ve federasyona, test, izleme ve yayına almaya uzanır.
Bu yol, arka uç ve ön uç geliştiricilerinin aynı GraphQL sözleşmesi etrafında çalışmasını hedefler. Kurumsal yazılım ekipleri hem sunucu hem istemci katmanını aynı program içinde öğrenerek ortak bir şema yaklaşımı oluşturabilir.
İlgili Mindset programı
Apollo GraphQL ile İstemci ve Sunucu Geliştirme
Sık sorulan sorular
Apollo Client için React şart mı?
Apollo Client çekirdek olarak çerçeveden bağımsızdır; sorguyu çalıştırır ve önbelleği yönetir. Hook'lar ise React için sunulan katmandır. Başka çerçevelerde ya da React dışında kullanmak mümkündür, ama bu sayfadaki useQuery ve useMutation örnekleri React içindir.
Apollo Client ile fetch kullanmak arasında ne fark var?
Fetch yalnızca isteği gönderir. Apollo ise sonucu normalleştirilmiş bir önbellekte tutar, aynı veriyi kullanan bileşenleri otomatik günceller, yükleme ve hata durumlarını sunar ve mutasyon sonrası önbellek güncelleme araçları verir. Bu işlerin hepsini elle yazmak büyük projelerde bakım yükü yaratır.
Önbellek neden bazen eski veriyi gösteriyor?
En sık neden, mutasyon yanıtında nesnenin id alanının dönmemesi ya da liste sorgusunun mutasyondan sonra güncellenmemesidir. Mutasyon yanıtına id ve değişen alanları ekleyin; listeyi güncellemek için refetchQueries ya da update işlevinde cache.modify kullanın.
Apollo Client yerine hangi alternatifler var?
GraphQL için başka istemci kütüphaneleri ve TanStack Query gibi sunucu durumu kütüphaneleri alternatiftir. Seçim, projedeki önbellek gereksinimine, ekibin tecrübesine ve GraphQL özelliklerine (abonelik, normalleştirme) ihtiyaca bağlıdır.