Durum Yönetimi Neden Frontend'in En Zor Sorunlarından Biri
Uygulamalar birçok gerçeklik kaynağı, asenkron veri, UI etkileşimi ve performans ödünleriyle uğraştığı için durum yönetimi zordur. Hataları azaltmak için kalıpları öğrenin.

Ön yüzde (frontend) uygulamada “Durum” Gerçekte Ne Anlama Gelir
Düz dilde tanım
Bir frontend uygulamada durum, basitçe arayüzünüzün bağlı olduğu ve zaman içinde değişebilen veridir.
Durum değiştiğinde ekranın buna uyum sağlaması gerekir. Ekran güncellenmezse, tutarsız güncellenir ya da eski ve yeni değerlerin karışımını gösterirse, “durum problemlerini” hemen hissedersiniz—butonlar kilitli kalır, toplamlar tutmaz veya görünüm kullanıcının yaptığı işlemi yansıtmaz.
Her gün gördüğünüz yaygın örnekler
Durum hem küçük hem de büyük etkileşimlerde ortaya çıkar, örneğin:
- Form alanları: kullanıcının yazdıkları, bir onay kutusunun işaretli olup olmadığı, hangi hataların gösterileceği
- Gezinme seçimleri: seçili sekme, bir sihirbazdaki (wizard) geçerli adım, açılıp kapatılan bölümler
- Alışveriş/sepet verileri: ürünler, miktarlar, uygulanan kuponlar, hesaplanan toplamlar
- Kullanıcı oturumu: giriş yapmış kullanıcı bilgisi, izinler, özellik bayrakları, “beni hatırla” tercihleri
Bunların bazıları “geçici” (ör. seçili sekme) iken bazıları “önemli” hissi verir (ör. sepet). Hepsi durumdur çünkü şu anda UI'ın ne göstereceğini etkilerler.
Durum, “bir bileşendeki değişkenler”den daha fazlasıdır
Basit bir değişken sadece yaşadığı yere bağlıdır. Durum farklıdır çünkü kuralları vardır:
- Sahiplik: hangi uygulama parçasının onu değiştirmeye yetkisi var
- Güncelleme akışı: değişiklikler ne zaman ve nasıl yeniden render tetikler
- Tutarlılık: birden fazla UI parçasının uyumunu sağlama
Durum yönetiminin gerçek amacı veri depolamak değil—güncellemeleri öngörülebilir kılmak, böylece UI tutarlı kalır. “Ne değişti, ne zaman ve neden?” sorularına cevap verebildiğinizde durum yönetilebilir olur. Cevap veremediğinizde, basit özellikler bile sürprizlere dönüşür.
Durum Başta Kolay Gelir (Sonra Birden Biter)
Bir frontend projesinin başında durum neredeyse sıkıcı derecede basit gelir—iyi anlamda. Tek bir bileşeniniz, tek bir girişiniz ve tek bir güncellemeniz vardır. Kullanıcı bir alana yazı yazar, siz değeri kaydedersiniz ve UI yeniden render olur. Her şey görünür, anlık ve kapsayıcıdır.
Basit örnek: tek bileşen, tek güncelleme
Tek bir metin girişi düşünün, yazdığınızı önizliyor:
- Durum, girişi render eden aynı bileşende yaşar.
- Güncelleme doğrudan kullanıcı eylemine cevaben olur.
- “Verinin sahibi kim?” hakkında tartışma yoktur.
Bu kurulumda durum temelde: zaman içinde değişen bir değişkendir. Nerede saklandığını ve nerede güncellendiğini gösterebilirsiniz, hepsi bu.
Yerel bileşen durumu neden basit gelir
Yerel durum işe yarar çünkü zihinsel model kod yapısıyla eşleşir:
- Kapsam küçüktür (bir bileşen, belki birkaç çocuk).
- Güncellemeler kullanıcı açısından eşzamanlı görünür.
- Veri akışı açıktır: input → güncelleme → render.
React gibi bir çerçeve kullanıyor olsanız bile, mimari hakkında derin düşünmenize gerek yoktur. Varsayılanlar çoğu durumda yeterlidir.
Uygulama büyüdükçe ne değişir
Uygulama “bir widget olan bir sayfa” olmaktan çıkıp “bir ürün” haline gelir gelmez, durum tek bir yerde yaşamayı bırakır.
Aynı veri artık şu yerlerde gerekebilir:
- birden fazla ekran (navigasyon)
- uzak bileşenler (paylaşılan UI)
- yeniden yüklemeler ve yeniden başlatmalar (kalıcılık)
- birden fazla kullanıcı/cihaz (sunucu senkronizasyonu)
Bir profil adı üst bilgide gösterilebilir, ayarlar sayfasında düzenlenebilir, daha hızlı yükleme için önbelleğe alınabilir ve karşılama mesajını kişiselleştirmek için kullanılabilir. Artık soru “bu değeri nasıl saklarım?” değil, “bu değer nerede yaşamalı ki her yerde doğru kalsın?” olur.
Karmaşıklık doğrusal olarak artmaz, sıçrar
Durum karmaşıklığı özelliklerle birlikte kademeli artmaz—ani sıçramalar olur.
Aynı veriyi okuyan ikinci bir yer eklemek “iki kat daha zor” değildir. Koordinasyon sorunları getirir: görünümleri tutarlı tutma, eski değerleri önleme, kimin neyi güncelleyeceğine karar verme ve zamanlamayı ele alma. Birkaç paylaşılan durum parçası ve asenkron işler olduğunda, tek tek her özellik basit gözükse de davranışları anlamak zorlaşır.
Çok Fazla Gerçeklik Kaynağı (Sources of Truth)
Aynı “olgu”nun birden fazla yerde saklandığı durumlarda işler acı verici olur. Her kopya sürüklenebilir ve artık UI kendi içinde çelişir hale gelir.
Yaygın şüpheliler
Çoğu uygulama birkaç yerde “gerçek” tutabilir:
- Sunucu verisi (API/veritabanı): kanonik kayıt
- İstemci önbelleği (örn. veri getirme kütüphanesi önbelleği): yerel bir ayna, yenilenmesi gerekir
- Yerel UI durumu (bileşen durumu): kullanıcının şu an yaptığı
- URL (path, query params, hash): yer işaretlenebilir, paylaşılabilir ve geri yüklenebilir durum
Bunların her biri bazı durumlar için geçerli sahibidir. Sorun, hepsi aynı durumu sahiplenmeye çalıştığında başlar.
Kopyalanma nasıl olur
Yaygın bir örnek: sunucudan veri alınır, sonra “düzenlemek için” yerel duruma kopyalanır. Örneğin bir kullanıcı profili yüklenir ve formState = userFromApi yapılır. Daha sonra sunucu tekrar sorgulanır (veya başka bir sekmede kayıt güncellenir) ve artık iki versiyonunuz olur: önbellek bir şey söyler, form başka bir şey.
Kopyalanma ayrıca “yardımcı” dönüşümlerle de girer: hem items hem de itemsCount saklamak, ya da hem selectedId hem de selectedItem tutmak gibi.
Tanıyacağınız semptomlar
Birden fazla gerçeklik kaynağı olduğunda hatalar genellikle şöyle seslenir:
- “Sadece bu ekranda çalışıyor.”
- Navigasyon veya yenileme sonrası UI tutarsız.
- Bir bileşende veri doğru görünür ama başka birinde eski.
- Kaydetme başarılı ama liste görünümü güncellenmiyor (ya da iki kez güncelleniyor).
Kural
Her durum parçası için bir sahip seçin—güncellemelerin yapıldığı yer—ve diğer herkesi projeksiyon (salt okunur, türetilmiş veya tek yönlü senkronize) olarak ele alın. Sahibini işaret edemiyorsanız, muhtemelen aynı gerçeği iki kez saklıyorsunuz.
Asenkron İşler ve Yan Etkiler Durumu Zora Sokar
Birçok frontend durumu basit görünür çünkü eşzamanlıdır: kullanıcı tıklar, siz bir değeri ayarlarsınız, UI güncellenir. Yan etkiler bu düzenli adım-adım hikâyeyi bozar.
Yan etki sayılanlar nelerdir?
Yan etkiler, bileşenin saf “veriye göre render etme” modelinin dışına çıkan her eylemdir:
- Ağ çağrıları (fetch, kaydetme, yeniden deneme)
- Zamanlayıcılar ve debounce (setTimeout, interval)
- Abonelikler (web socketler, event listenerlar)
- Tarayıcı depolama (localStorage/sessionStorage)
Her biri daha sonra tetiklenebilir, beklenmedik şekilde başarısız olabilir veya birden çok kez çalışabilir.
Asenkron durum neden senkron durumdan daha zordur
Asenkron güncellemeler zaman değişkenini tanıtır. Artık “ne oldu” değil, “hala ne oluyor olabilir” diye düşünürsünüz. İki istek üst üste gelebilir. Yavaş bir yanıt daha yenisinden sonra gelebilir. Bir bileşen unmount olurken asenkron geri çağrı hâlâ durumu güncellemeye çalışabilir.
Bu yüzden hatalar genellikle şöyle görünür:
- Yükleme bayrakları sonsuza dek takılı kalır (hata yolu temizlenmedi ya da istek iptal edildi)
- UI eski veriyi flaş eder (önbelleğe alınmış değer “son” olarak gösterilir)
- Eski yanıtlar yeni olanların üzerine yazar (istek A, B'den sonra biter)
Basit bir strateji: isteği açıkça modelleyin
isLoading gibi boolean’ları her yere saçmak yerine asenkron işi küçük bir durum makinesi gibi ele alın:
- idle (hiçbir şey başlamadı)
- loading (devam ediyor)
- success (veri hazır)
- error (hata yakalandı)
Veri ve durum bilgisini birlikte takip edin ve geç kalan yanıtları göz ardı edebilmek için bir tane tanımlayıcı (istek id'si veya sorgu anahtarı) saklayın. Bu, “şu anda UI ne göstermeli?” sorusunu tahminden çıkarır.
UI Durumu vs Sunucu Durumu (Benzer Görünür, Ama Farklıdır)
Birçok durum sorunu basit bir karışmadan kaynaklanır: “kullanıcının şu an yaptığı” ile “backend'in doğru dediği” aynıymış gibi davranmak. Her ikisi de zamanla değişebilir, ama kuralları farklıdır.
UI durumu: arayüzün şu an ne yaptığı
UI durumu geçici ve etkileşim odaklıdır. Ekranı kullanıcının beklentisine uygun şekilde o an göstermek için vardır.
Örnekler: açık/kapalı modal, aktif filtreler, arama girişi taslağı, hover/focus durumları, hangi sekmenin seçili olduğu ve sayfalama UI'ı (geçerli sayfa, sayfa büyüklüğü, kaydırma pozisyonu).
Bu durum genellikle bir sayfa veya bileşen ağacına özgüdür. Navigasyonla sıfırlanması sorun değildir.
Sunucu durumu: aldığınız veri (ve başka yerden değişebilecek olan)
Sunucu durumu API'dan gelen verilerdir: kullanıcı profilleri, ürün listeleri, izinler, bildirimler, kaydedilmiş ayarlar. Bu “uzaktan doğruluk”tır ve UI hiçbir şey yapmasa bile değişebilir (başkası düzenler, sunucu yeniden hesaplar, arka plan işi günceller).
Uzaktan olduğu için metadata gerekir: yükleme/hata durumları, önbellek zaman damgaları, yeniden denemeler ve geçersiz kılma (invalidation).
Karıştırmak neden kafa karıştırır
UI taslaklarını sunucu verisinin içine koyarsanız, bir refetch yerel düzenlemeleri silebilir. Sunucu yanıtlarını UI durumuna önbellekleme kuralları olmadan koyarsanız eski veri, tekrar eden fetch'ler ve tutarsız ekranlarla uğraşırsınız.
Yaygın bir başarısızlık modu: kullanıcı bir formu düzenlerken arka planda refetch gelir ve gelen cevap taslağın üzerine yazar.
Pratik bir kılavuz
Sunucu durumunu önbellekleme kalıplarıyla yönetin (fetch, cache, invalidate, focus ile refetch) ve bunu paylaşılan ve asenkron olarak ele alın.
UI durumunu yerel araçlarla yönetin (yerel bileşen durumu, gerçekten paylaşılan UI endişeleri için context) ve taslakları bilinçli olarak sunucuya “kaydet” deyinceye kadar ayrı tutun.
Türetilmiş Durum ve “Hesaplayabileceğini Saklama” Kuralı
Türetilmiş durum, diğer durumlardan hesaplayabileceğiniz herhangi bir değerdir: satır öğelerinden sepet toplamı, orijinal liste + arama sorgusundan filtrelenmiş liste veya alan değerleri ve doğrulama kurallarından canSubmit bayrağı.
Bu değerleri saklamak cazip gelir çünkü pratik görünür (“ben de total'ı state'te tutarım”). Ama girdiler birden fazla yerde değiştiğinde sapma riski ortaya çıkar: saklanan total artık öğelerle eşleşmez, filtrelenmiş liste mevcut sorguyu yansıtmaz veya gönder butonu hatayı düzelttikten sonra hâlâ devre dışı kalır. Bu hatalar sinir bozucudur çünkü tek başına hiçbir şey “yanlış” görünmez—her değişken kendi başına geçerli ama birbirleriyle uyumsuzdur.
Seçiciler / hesaplanan değerleri tercih edin
Daha güvenli bir desen: minimal kaynakları saklayın ve geri okuma sırasında her şeyi hesaplayın. React'te bu basit bir fonksiyon olabilir veya memoize edilmiş bir hesaplama.
const items = useCartItems();
const total = items.reduce((sum, item) => sum + item.price * item.qty, 0);
const filtered = products.filter(p => p.name.includes(query));
Daha büyük uygulamalarda “seçiciler” (selectors) bu fikri resmileştirir: total, filteredProducts, visibleTodos nasıl türetileceğini tek bir yerde tanımlayan ve tüm bileşenlerin aynı mantığı kullanmasını sağlayan bir yapı.
Türetilmiş değerleri önbelleğe almak ne zaman uygundur
Her render'da hesaplamak genelde iyidir. Gerçek bir maliyet ölçtüğünüzde önbelleğe alın: pahalı dönüşümler, devasa listeler veya birçok bileşen tarafından paylaşılan türetilmiş değerler. Memoizasyon (useMemo, selector memoizasyonu) kullanın; aksi halde gerçek girdiler dışındaki anahtarlarla cache yaparsanız yeniden sapma riski doğar.
Küresel vs Yerel: Doğru Sahibi Seçmek
Durum, “sahibi kim” belirsiz olduğunda can sıkıcı olur.
“Sahiplik” ne demektir
Bir durum parçasının sahibi, onu güncelleme hakkına sahip olan uygulama yeridir. Diğer UI parçaları onu okuyabilir (props, context, selector aracılığıyla), ama doğrudan değiştirmemelidir.
Açık sahiplik şu iki soruyu yanıtlar:
- Bu değeri kim güncelleyebilir? (sahibi)
- Bu değeri kim okuyabilir? (tüketiciler)
Bu sınırlar bulanıklaşırsa çakışan güncellemeler, “bunu neden değiştirdi?” anları ve yeniden kullanılabilirliği zor bileşenler elde edersiniz.
Küresel durum: kullanışlı ama bağlılık (coupling) sızar
Durumu global bir store'a (veya üst seviye context'e) koymak temiz gelebilir: herkes ona erişir ve prop zincirini azaltırsınız. Ancak bedel istemeden bağlılıktir—ilişkisiz ekranlar aynı değerlere bağlanır ve küçük değişiklikler uygulama boyunca dalga etkisi yapar.
Küresel durum, gerçekten çapraz kesen (cross-cutting) şeyler için uygundur: geçerli kullanıcı oturumu, uygulama düzeyi özellik bayrakları veya paylaşılan bildirim kuyruğu gibi.
Durumu sadece gerektiği kadar yukarı taşıyın
Yaygın bir desen yerelde başlamak ve iki kardeş parça koordinasyona ihtiyaç duyduğunda en yakın ortak üst elemana “lift” etmektir.
Eğer sadece bir bileşen ihtiyaç duyuyorsa, orada tutun. Birden fazla bileşen gerekiyorsa en küçük ortak sahipliğe taşıyın. Birçok uzak alan gerekiyorsa o zaman küresel düşünün.
Basit bir sezgi kuralı
Durumu kullanıldığı yere yakın tutun; paylaşım gerekmedikçe küreselleştirmeyin.
Bu, bileşenleri anlamayı kolaylaştırır, istemeden bağımlılıkları azaltır ve gelecekteki refaktörleri daha az korkutucu kılar çünkü daha az parça aynı veriyi değiştirme yetkisine sahiptir.
Eşzamanlılık, Yarışlar ve Sıra Dışı Güncellemeler
Frontend uygulamalar tek iş parçacıklı (single-threaded) hissedilir, ama kullanıcı girdisi, zamanlayıcılar, animasyonlar ve ağ istekleri bağımsız çalışır. Bu, birden fazla güncellemenin aynı anda yolda olabileceği ve başladıkları sırayla bitmeyebileceği anlamına gelir.
Güncellemeler çarpıştığında
Yaygın bir çarpışma: UI'nın iki parçası aynı durumu güncelliyor.
- Bir arama kutusu her tuş vuruşunda
query'yi güncelliyor. - Bir filtre açılır menüsü değiştiğinde aynı sonuç listesini etkileyen
query'yi güncelliyor.
Her biri tek başına doğruyken birlikte zamanlamaya bağlı olarak birbirlerinin üzerine yazabilir. Daha da kötüsü, yeni filtreleri gösterirken eski bir sorgunun sonuçlarını gösterebilirsiniz.
Yarış koşulları: hızlı kullanıcılar, yavaş ağlar
Yarış koşulları, istek A'yı gönderdikten sonra hızla istek B'yi göndermeniz ama istek A'nın son gelmesi durumunda ortaya çıkar.
Örnek: kullanıcı “c”, “ca”, “cat” yazıyor. Eğer “c” isteği yavaş, “cat” isteği hızlıysa UI önce “cat” sonuçlarını gösterip sonra eski “c” sonuçlarının gelmesiyle üzerine yazılabilir.
Hata ince çünkü her şey “çalıştı”—sadece yanlış sırada oldu.
Sıra dışı hataları azaltan teknikler
Genellikle şu stratejilerden birini istersiniz:
- Yeni bir istek geldiğinde öncekini iptal edin (ör.
AbortControllerile). - Eski yanıtları görmezden gelin; yanıtın hâlâ en son girdiye uyup uymadığını kontrol edin.
- İstek ID'leri / sıra numaraları kullanın ve sadece en yeni olanı kabul edin.
Basit bir istek ID yaklaşımı:
let latestRequestId = 0;
async function fetchResults(query) {
const requestId = ++latestRequestId;
const res = await fetch(`/api/search?q=${encodeURIComponent(query)}`);
const data = await res.json();
if (requestId !== latestRequestId) return; // stale response
setResults(data);
}
Optimizm (optimistic updates) ve nasıl yanlış gider
Optimizm UI'ı anlık hissettirir: sunucu onayından önce ekranı güncellersiniz. Ancak eşzamanlılık varsayımlarını bozabilir:
- Kullanıcı “Beğen”e iki kez hızlıca tıklar (beğen → beğenme), ama istekler ters sırada sonuçlanır.
- Stoğu optimistik olarak azaltırsınız, sonra daha sonra bir hata dönüp geri alma gerekir—ancak kullanıcı zaten başka değişiklikler yaptı veya sayfadan ayrıldı.
Optimizmi güvenli tutmak için genellikle açık bir uzlaşma kuralı gerekir: bekleyen eylemi takip edin, sunucu yanıtlarını sırayla uygulayın ve rollback gerekirse bilinen bir kontrol noktasına (checkpoint) geri dönün—not “UI şu an ne gösteriyorsa ona”.
Performans: Durum Değişiklikleri Çok Pahalı Olduğunda
Durum güncellemeleri “bedava” değildir. Durum değiştiğinde uygulama hangi ekran parçalarının etkilendiğini bulup yeni gerçeği yansıtmak için işe koyulur: değerleri yeniden hesaplar, UI'ı yeniden render eder, formatlama mantığını çalıştırır ve bazen veri tekrar alır veya doğrular. Bu zincir reaksiyonu gereğinden fazla büyükse kullanıcı bunu gecikme, takılma veya butonların tepkiyi “düşünmesi” olarak hisseder.
Küçük bir değişiklik neden büyük hissettirir
Tek bir anahtar bile gereksiz yere çok fazla işi tetikleyebilir:
- UI'nın büyük bölümleri yeniden render olur, oysa sadece küçük bir parça değişmişti.
- Listeler yeniden çizilip ölçülür, kaydırma takılmasına neden olur.
- Nesne ve diziler her güncellemede yeniden yaratılır (“derin churn”), böylece uygulama neyin gerçekten farklı olduğunu kolayca anlayamaz.
Sonuç sadece teknik değildir—deneyimsel olarak hissedilir: yazma gecikir, animasyonlar takılır ve arayüzin “hızlı” olduğu hissi kaybolur.
Yaygın performans tuzakları
En yaygın nedenlerden biri durumu aşırı geniş tutmaktır: birçok ilgisiz bilgiyi içeren büyük bir “kova” obje. Her alan güncellendiğinde tüm kova yenilenmiş gibi görünür ve daha fazla UI uyanır.
Bir diğer tuzak türetilmiş değerleri state'te tutmaktır. Bu genellikle ekstra güncellemelere (ve ekstra UI işine) yol açar sadece her şeyi uyumlu tutmak için.
UI'ı hızlı tutan taktikler
Durumu daha küçük parçalara ayırın. İlgisiz endişeleri ayrı tutun ki arama girişi tüm sayfayı yenilemesin.
Verileri normalize edin. Aynı öğeyi birçok yerde tutmak yerine bir kere saklayıp referans verin. Bu tekrar eden güncellemeleri azaltır ve bir düzenlemenin birçok kopyayı yeniden yazmasına engel olur.
Türetilmiş değerleri memoize edin. Bir değer diğer durumdan hesaplanabiliyorsa (örn. filtrelenmiş sonuçlar), sadece girdiler değiştiğinde yeniden hesaplanacak şekilde cacheleyin.
Amaç: daha az takılma, daha az sürpriz
İyi performans odaklı durum yönetimi büyük ölçüde kapsayıcılıkla ilgilidir: güncellemeler mümkün olan en küçük alanı etkilemeli ve pahalı işler gerçekten gerektiğinde çalışmalıdır. Bunu sağladığınızda kullanıcılar çerçeveyi fark etmeyi bırakır ve arayüze güvenmeye başlar.
Durumu Tahminlemeden Hata Ayıklama ve Test Etme
Durum hataları çoğunlukla kişisel hissedilir: UI “yanlış”, ama en basit soruyu yanıtlayamazsınız—bu değeri kim ve ne zaman değiştirdi? Bir sayı ters döndüğünde, bir banner kaybolduğunda veya bir buton kilitlendiğinde bir zaman çizelgesine ihtiyacınız var, tahmine değil.
Değişiklikleri izlenebilir kılın (gizemli değil)
En hızlı açıklık yolu öngörülebilir bir güncelleme akışıdır. Reducer, event veya store kullanın; şu deseni hedefleyin:
- Değişiklikler küçük, iyi adlandırılmış eylemlerle olsun (rastgele mutasyonlar değil)
- Her eylemin net bir payload'u olsun (
setShippingMethod('express'),updateStuffyerine) - Eylemleri ve ortaya çıkan durum geçişlerini tutarlı şekilde loglayın
Açık eylem kaydı (action logging), hata ayıklamayı “ekrana bakma”dan “fişi takip etmeye” çevirir. Basit console log'lar bile (eylem adı + ana alanlar) ne olduğunu yeniden kurmaya çalışmaktan daha iyidir.
Mantığın sabit olduğu yerleri test edin
Her yeniden render'ı test etmeye çalışmayın. Bunun yerine saf mantık gibi davranması gereken parçaları test edin:
- Reducer / durum güncelleyicilerini birim test ile test edin: önceki durum + eylem verildiğinde sonraki durumu doğrulayın
- Seçiciler / türetilmiş hesaplamaları test edin: verilen durum için beklenen çıktıyı doğrulayın
- Ana kullanıcı akışlarını entegrasyon testi ile doğrulayın: giriş → veri yükleme → düzenleme → kaydetme → onay görme
Bu karışım hem “hesaplama hatalarını” hem de gerçek dünyadaki bağlantı sorunlarını yakalar.
Asenkron hatalar için hafif enstrümantasyon ekleyin
Asenkron problemler boşluklarda gizlenir. Zaman çizelgelerini görünür kılacak minimal metadata ekleyin:
- Önemli güncellemelere zaman damgası ekleyin
- İstek ID'leri (ID'yi eylemler ve cevaplarla ilişkilendirin)
Böylece geç gelen bir cevap daha yeni olanın üzerine yazdığında bunu hemen ispatlayabilirsiniz—ve güvenle düzeltebilirsiniz.
Durum Yönetimi Yaklaşımı Seçmek (Araç Kavgaları Olmadan)
Bir durum aracını seçmek, kararların bir sonucu olarak daha kolaydır—araçları karşılaştırmakla başlamak yerine sınırları haritalayın: hangi veriler bileşene yerel, hangileri paylaşılıyor ve hangileri gerçekten “sunucu verisi”.
Önemli seçim kriterleri
Pratik bir karar için birkaç kısıtı göz önüne alın:
- Uygulama büyüklüğü ve ömrü: küçük bir dahili araç basit kalabilir; uzun ömürlü bir ürün daha güçlü konvansiyonlardan fayda sağlar
- Ekip alışkanlıkları: ekibinizin tutarlı kullanabileceği bir şeyi seçin
- Asenkron ihtiyaçlar: yoğun fetch, cache, sayfalama ve mutasyonlar denklemi değiştirir
- Durum karmaşıklığı: sayfalar arası iş akışları, geri al/yinele (undo/redo) ve çok adımlı formlar daha fazla yapı gerektirir
Yüksek seviyeli karşılaştırma (ideoloji yok)
- Context + hooks: bağımlılık enjeksiyonu ve düşük frekanslı paylaşılan değerler (tema, auth) için harika. Ancak sık güncellemeler ek gürültü yaratabilir.
- Redux tarzı store'lar: güçlü konvansiyonlar, öngörülebilir güncellemeler ve iyi araçlar. Özellikle denetim izi veya kompleks koordinasyon gerekliyse iyidir.
- Atom tabanlı store'lar (ince taneli): çok sayıda reducer yazmadan paylaşılabilir durum için ergonomik. Kademeli olarak ölçeklendirmesi genelde kolaydır.
- Query cache'leri (sunucu-durumu araçları): fetch, cache, dedupe, arka planda refetch ve mutasyonlar için özelleşmiş. Çok miktarda “async glue code” ihtiyacını azaltır.
Aracı ilk düşünme tuzağından kaçının
“Her yerde X kullanıyoruz” diye başlarsanız yanlış şeyleri yanlış yere saklarsınız. Önce sahiplik ile başlayın: bu değeri kim güncelliyor, kim okuyor ve değiştiğinde ne olmalı?
Araçları birleştirmek genelde en iyi yaklaşımdır
Birçok uygulama API verileri için bir server-state kütüphanesi ile yerel UI endişeleri için küçük bir çözüm kombinasyonuyla iyi gider. Amaç açıktır: her tür durum, akıl yürütülmesi en kolay yerde yaşasın.
Koder.ai bu noktada nerede durur
Durum sınırları ve asenkron akışlar üzerinde iterasyon yapıyorsanız, Koder.ai deneme-izleme-düzeltme döngüsünü hızlandırabilir. Agent tabanlı iş akışıyla sohbet içinde React frontend (ve Go + PostgreSQL backend) üreterek farklı sahiplik modellerini (yerel vs küresel, sunucu önbelleği vs UI taslakları) hızlıca prototipleyip, öyle kalanı seçebilirsiniz.
Deney yaparken yardımcı iki pratik özellik: Planning Mode (durum modelini inşa etmeden önce taslak oluşturmak için) ve snapshots + rollback (türetilmiş durumu kaldırma veya istek ID'leri ekleme gibi refaktörleri kaybedip geri dönebileceğiniz güvenli testler için).
Durumu Daha Az Ağır Hale Getirmek İçin Pratik Kontrol Listesi
Durum tasarımını bir problem olarak ele aldığınızda işler kolaylaşır: kimin sahip olduğunu, neyi temsil ettiğini ve nasıl değiştiğini kararlaştırın. Bir bileşen gizemli hissetmeye başladığında bu kontrol listesini kullanın.
1) Sahipliği ve tek gerçek kaynağı netleştirin
Sorun: Bu verinin sorumlusu uygulamanın hangi parçası? Durumu kullanıldığı yere mümkün olduğunca yakın koyun ve yalnızca gerçekten paylaşım gerekiyorsa yukarı taşıyın.
- Her durum parçası için bir sahip.
- Veriyi aşağı geçirin; değişiklikleri callback/event ile yukarı gönderin.
- İki yer aynı değeri güncelleyebiliyorsa, gerçeklik kaynağınız yok—çatışma bekleyin.
2) Kopyalamaktan kaçının ve türetilmiş değerleri modelleyin
Bir şeyi diğer durumdan hesaplayabiliyorsanız saklamayın.
- Minimal girdileri saklayın (örn.
items,filterText). - Çıktıları render sırasında veya memo ile hesaplayın (örn.
visibleItems).
3) Asenkron durumları açıkça modelleyin (örtük değil)
Asenkron işler daha net olduğunda daha kolay anlaşılır:
- Küçük bir “istek durumu” şekli tercih edin:
status: 'idle' | 'loading' | 'success' | 'error', artıdataveerror. - “Loading” ve “error”u birinci sınıf UI durumları gibi ele alın, saçma boolean'lara yaymayın.
4) Yaygın antipattern'lere dikkat edin
- Propsları güvenlik için state'e kopyalamak (drift yaratır).
- Her şeyi global yapmak (ilişkisiz ekranları bağlar).
- Boolean çorbası (
isLoading,isFetching,isSaving,hasLoaded, …) yerine tek birstatuskullanın.
5) Küçük, güvenli adımlarla refaktör edin
- Karışık durumları ayırın: UI endişelerini (açık/kapalı, giriş metni) sunucu verisinden ayırın.
- Türetilmiş değerleri silin ve gerçek kaynaktan hesaplayın.
- Yan etkileri (fetch, abonelikler) özellik başına bir yerde merkezileştirin.
Pratik hedefler
Amaç: “bu duruma nasıl geldi?” hatalarını azaltmak, beş dosyaya dokunmadan değişiklik yapabilmek ve tek bir yere işaret edip burada gerçeklik yaşıyor diyebildiğiniz bir zihinsel model geliştirmek.
SSS
Bir frontend uygulamasında state ne anlama gelir?
State, form değerleri, açık bir modal, seçili sekme veya sepetteki ürünler gibi kullanıcıların gördüklerini belirleyen değişen verilerdir. Değiştiğinde, arayüz bu veriyi kullanan her yerde yeni değeri göstermelidir.
Bir uygulama büyüdükçe state yönetimi neden zorlaşır?
Sorunlar, aynı verinin ekranlar arasında çalışması, yeniden yüklemelerden sonra korunması veya bir API ile eşitlenmesi gerektiğinde başlar. Bu durumda verinin nerede tutulacağı ve hangi güncellemelerin geçerli olacağı için net kurallara ihtiyacınız olur.
Tek doğruluk kaynağı nedir?
Her bilginin tek bir sahibi olsun. Diğer bileşenler kendi düzenlenebilir kopyalarını tutmak yerine bu verinin hesaplanmış veya eşitlenmiş görünümünü okumalıdır.
Global state yerine ne zaman local state kullanmalıyım?
Arayüz durumunu kullanan bileşene veya sayfaya yakın tutun. Yakındaki bölümlerin eşgüdüm içinde çalışması gerektiğinde bunu ortak bir üst bileşene taşıyın ve global state'i yalnızca birbirinden uzak birçok alanın gerçekten paylaştığı bilgiler için kullanın.
UI state ile server state arasındaki fark nedir?
UI state, açık bir iletişim kutusu, etkin sekme veya kaydedilmemiş arama metni gibi mevcut etkileşimi tanımlar. Server state bir API'den gelir ve veri çekme, önbellekleme, hata yönetimi ve yenileme kuralları gerektirir.
Sepet toplamları gibi türetilmiş değerleri state içinde saklamalı mıyım?
Genellikle hayır. Toplamları, filtrelenmiş listeleri ve doğrulama sonuçlarını girdilerinden hesaplayın; böylece eşzamanlılıklarını kaybetmezler. Bir hesaplamayı ancak gerçek bir performans maliyeti belirledikten sonra önbelleğe alın.
Yüklenme ve hata durumlarını nasıl yönetmeliyim?
İsteği, veri ve hata bilgileriyle birlikte boşta, yükleniyor, başarılı veya hatalı gibi bir durumla doğrudan modelleyin. Böylece arayüz, isteğin her aşamasında göstereceği net bir duruma sahip olur.
Eski API yanıtlarının yeni verilerin üzerine yazmasını nasıl önlerim?
Mümkünse eski isteği iptal edin veya bir istek kimliği ekleyin ve yalnızca en son istekle eşleşiyorsa yanıtı kabul edin. Bu, daha eski ve yavaş bir yanıtın daha yeni sonuçların yerini almasını engeller.
Küçük bir state güncellemesi UI'ımı neden yavaşlatabilir?
İlişkisiz state'i daha küçük parçalara ayırın ve gerekmedikçe büyük nesneleri veya dizileri yeniden oluşturmayın. Özellikle büyük listelerde, maliyetli filtrelenmiş veya dönüştürülmüş verileri yalnızca gerçek girdileri değiştiğinde hesaplayın.
Bir state yönetim aracını nasıl seçerim?
Araçları, sahipliği ve veri türünü belirledikten sonra seçin. Bir query cache API verileri için, local state bileşen etkileşimleri için uygundur; birçok özellik eşgüdümlü istemci taraflı güncellemelere ihtiyaç duyduğunda ise bir store yardımcı olur.