Diyarbakır Yazılım LogoDİYARBAKIR
>Ana Sayfa>Projeler>Atölye>Yazılar
>Ana Sayfa>Projeler>Atölye>Yazılar
durum: inşa ediliyor
Next.js'te State Management: Kurumsal Ölçekli Çözümler
  1. Anasayfa
  2. Yazılar
  3. Next.js'te State Management: Kurumsal Ölçekli Çözümler

Next.js'te State Management: Kurumsal Ölçekli Çözümler

Diyarbakır Yazılım
Diyarbakır Yazılım
16.08.2026
#Yazılım#Teknoloji#Topluluk

Next.js projesinde state yönetimi konuşulmaya başladığında ilk refleks çoğu zaman Redux, Zustand veya başka bir kütüphane seçmek oluyor. On yıllık frontend ve kurumsal uygulama geliştirme deneyimimde ise en pahalı state sorunlarının yanlış kütüphaneden değil, verinin gerçek sahibinin yanlış belirlenmesinden çıktığını defalarca gördüm. Next.js'te State Management: Kurumsal Ölçekli Çözümler yaklaşımında önce verinin server'a mı, URL'ye mi, component'a mı, browser'a mı yoksa bir business workflow'a mı ait olduğunu ayıracağız. Ardından Redux Toolkit, Zustand, TanStack Query, React Context, Server Components ve Server Actions gibi araçları yalnız gerçekten çözdükleri probleme yerleştireceğiz. Yazının sonunda Next.js kurumsal projelerde state management nasıl yapılır sorusuna yalnız kütüphane ismiyle değil, source of truth, request isolation, cache, hydration, güvenlik, test ve gözlemlenebilirlik üzerinden cevap verebileceksiniz.

Next.js'te State Management Neden Klasik React'ten Farklıdır?

Klasik bir client-side React uygulamasında uygulamanın büyük bölümü browser içinde yaşadığı için state kararları çoğunlukla client sınırında verilir. Next.js App Router ise Server Components, Client Components, server rendering, route cache, Server Actions ve request bazlı çalışma modeli nedeniyle aynı düşünceyi doğrudan taşımayı riskli hâle getirir. Bir değer server tarafından zaten biliniyorsa onu global client store'a taşımak ikinci bir source of truth oluşturabilir ve cache invalidation sorunlarını büyütebilir. Bir değer request'e özelse module-level singleton store içine konması kullanıcılar arasında veri karışmasına kadar gidebilecek ciddi bir mimari hata oluşturabilir. Bu nedenle Next.js'te state management, “hangi store?” sorusundan önce “hangi environment bu verinin sahibi?” sorusuyla başlamalıdır.

App Router'ın State Mimarisine Etkisi

App Router, component ağacını server ve client tarafında farklı sorumluluklara ayırdığı için state ownership kararını doğrudan etkiler. Sayfa veya layout varsayılan olarak Server Component olabilir ve veriyi kaynağa yakın noktadan okuyabilir, böylece her server verisini browser store'a kopyalamak gerekmez. Client tarafında yalnız etkileşim, browser API veya canlı kullanıcı state'i gerektiğinde Client Component boundary açılır. Route parametreleri ve search params gibi navigation state'leri de framework tarafından doğal biçimde taşındığı için ayrı global store ihtiyacı azalır. Kurumsal projede App Router'ı yalnız yeni bir routing sistemi gibi görmek yerine state mimarisinin temel sınırlarından biri olarak ele almak daha sağlıklı sonuç verir.

Server Components ve Client Components Ayrımı

Server Components ve Client Components ayrımı, hangi state'in nerede yaşayacağını anlamanın en pratik yollarından biridir. Server Component database, güvenli backend API veya request bilgisine yakın çalışırken browser event'leri ve local interactive state ile ilgilenmez. Client Component ise click, input, drag, modal, browser storage ve gerçek zamanlı kullanıcı etkileşimi gibi ihtiyaçları yönetir. Server'dan Client Component'a veri props ile aktarılabilir, ancak bu veri client tarafında gerçek source of truth olmaktan çok başlangıç snapshot'ı niteliğinde olabilir. Bu sınırı doğru kurduğunuzda client bundle küçülür, hydration riski azalır ve global store'a gereksiz veri taşıma ihtiyacı önemli ölçüde düşer.

Server Component'ın Sahip Olması Gereken Veriler

Database'den okunan ürün kaydı, server tarafından doğrulanan session, tenant bilgisi ve güvenli backend credential gerektiren veriler Server Component tarafına daha doğal biçimde aittir. Bu verilerin browser store'a kopyalanması çoğu zaman güvenlik veya tutarlılık açısından ek sorun üretir. Server Component veriyi render eder, gerekli bölümü Client Component'a serializable prop olarak aktarır ve client yalnız kendisine gerekli snapshot ile çalışır. Mutation sonrasında server cache invalidation veya route revalidation uygulanarak yeni server gerçeği tekrar üretilir. Bu model, server-owned data'nın browser state sistemi tarafından sahiplenilmesini engeller ve source of truth sınırını belirgin tutar.

Client Component'ın Sahip Olması Gereken State

Modal açık mı, hangi accordion seçili, kullanıcı geçici olarak hangi filtre chip'ini işaretledi veya drag işleminin mevcut durumu nedir gibi bilgiler browser etkileşimine aittir. Bu state çoğu durumda `useState`, `useReducer` veya dar kapsamlı bir client store ile yönetilebilir. Kullanıcının henüz server'a göndermediği form alanları da doğal olarak client state örneğidir. Birden fazla uzak component aynı browser-owned state'i kullanıyorsa Zustand veya Redux Toolkit değerlendirilebilir, ancak tek component'a ait state'i global store'a çıkarmak gereksiz coupling oluşturur. Client state tasarımında asıl hedef her şeyi globalleştirmek değil, state'in ihtiyaç duyduğu en küçük yaşam alanını seçmektir.

'use client' Bir State Kararı Değil, Mimari Boundary'dir

`'use client'` bir dosyayı “state dosyası” hâline getiren işaret değildir, server ve client module graph arasında boundary tanımlar. Bu boundary'nin üst seviyeye taşınması, o dosyanın import ettiği client tarafı modüllerin browser bundle'ına dahil olmasına yol açabilir. Bu nedenle root layout'u sırf birkaç küçük interactive component için geniş bir Client Component'a çevirmek performans ve mimari bakım açısından pahalı olabilir. Daha doğru yaklaşım, interaction gereken leaf component'lerde boundary açmak ve server-rendered alanı mümkün olduğunca geniş tutmaktır. Provider, Zustand store veya Redux erişimi gerektiğinde client boundary kullanılır, fakat boundary'nin kapsamı gerçek ihtiyaç kadar dar tutulur.

Kurumsal Ölçekte Yanlış State Yerleşiminin Maliyeti

Küçük projede yanlış yere konan bir state yalnız birkaç gereksiz render üretebilir, büyük projede ise onlarca takımın bağımlı olduğu kalıcı mimari borca dönüşebilir. Server verisini Redux'a kopyalamak cache invalidation sorunları yaratırken request-specific veriyi singleton store'da tutmak isolation problemine yol açabilir. URL ile paylaşılması gereken filtreyi global store'da tutmak bookmark ve back button davranışını bozabilir. Local modal state'ini organization-wide store'a taşımak da component'ları store shape'e gereksiz bağlar ve refactoring alanını daraltır. Kurumsal ölçekte doğru state placement, performans kadar güvenlik, deploy bağımsızlığı, test maliyeti ve takım koordinasyonu açısından da temel mimari karardır.

Önce State'i Sınıflandırın, Sonra Kütüphane Seçin

State management değerlendirmesinde kullandığım en faydalı yöntem, teknoloji listesi açmadan önce bütün state kategorilerini envanter hâline getirmektir. Server-owned data, URL state, local UI state, shared browser state, form state ve workflow state aynı araçla yönetilmeye çalışıldığında store kısa sürede bütün uygulamanın veri deposuna dönüşür. Oysa her kategorinin yaşam süresi, source of truth'ı, persistence ihtiyacı ve invalidation modeli farklıdır. Next.js için Redux Zustand ve React Context karşılaştırması da ancak bu sınıflandırmadan sonra anlamlı sonuç verir. State sınıfı doğru belirlendiğinde çoğu zaman hangi aracın kullanılacağı tartışması şaşırtıcı derecede kolaylaşır.

Server-Owned State

Server-owned state'in gerçek kaynağı database, backend servis, authentication sistemi veya başka server-side veri kaynağıdır. Product catalog, user profile, permission listesi veya account billing bilgisi bu kategoriye girebilir. Client bu verinin yalnız bir kopyasını görür ve kalıcı gerçeği değiştirmek için mutation işlemini server'a gönderir. Server-owned state'i client store'un gerçek sahibi gibi modellemek iki ayrı gerçek yaratabilir. Next.js Server Components ve uygun cache modeli, bu verinin önemli bölümünü global client state'e sokmadan yönetmeye imkân verir.

Request State

Request state yalnız belirli HTTP isteği veya render akışı sırasında anlamlı olan veridir. Cookie, request header, authenticated user bağlamı, locale veya tenant tespiti buna örnek olabilir. Bu veri process-wide singleton store içinde tutulmamalıdır çünkü aynı server aynı anda birden fazla kullanıcı isteğini işleyebilir. Request state ya doğrudan server API'lerinden okunmalı ya da request scope içinde taşınmalıdır. Kurumsal güvenlik açısından request isolation kuralı state architecture checklist'inin en kritik maddelerinden biridir.

Server Cache State

Server cache state kalıcı business gerçeğin kendisi değil, server'ın veriyi belirli süre veya tag stratejisiyle tekrar kullanmak için tuttuğu temsilidir. Ürün listesi veya CMS içeriği cache üzerinden hızlı sunulabilir, ancak source of truth yine database veya dış servistir. Cache'in stale kalabileceği süre business freshness ihtiyacına göre belirlenmelidir. Mutation sonrası ilgili path veya tag invalidation yapılmadığında kullanıcı eski veri görebilir. Bu nedenle cache strategy state kütüphanesinden bağımsız ama state tutarlılığıyla doğrudan ilişkili bir mimari katmandır.

URL State

Arama, pagination, sort ve filtre gibi kullanıcı tarafından paylaşılması veya bookmark edilmesi beklenen değerler URL state için güçlü adaydır. URL zaten browser history, deep link ve back button davranışını çözer. Bu state'i ayrıca Redux veya Zustand içinde tutarsanız URL ile store arasında senkronizasyon problemi oluşturabilirsiniz. Next.js App Router `searchParams` ve route parametreleri bu tür state'in doğal kaynağı olarak kullanılabilir. URL state'i doğru kullanmak global client store'un gereksiz büyümesini engelleyen en pratik yöntemlerden biridir.

Local UI State

Tek component veya küçük subtree içinde kullanılan state local UI state kategorisine girer. Modal görünürlüğü, tooltip durumu, input focus veya accordion seçimi gibi bilgiler çoğu zaman `useState` ile rahatça yönetilir. Bu state'i global store'a taşımak component'ın başka feature'lara gereksiz bağımlılık geliştirmesine neden olabilir. Local state component unmount olduğunda doğal biçimde temizlenir ve route değişiminde eski state taşıma riski azalır. State'in ihtiyaç duyduğu en dar scope'u kullanmak kurumsal projelerde de güçlü varsayılandır.

Shared Client State

Birden fazla uzak Client Component'ın aynı browser-owned ve mutable veriye ihtiyacı varsa shared client state ihtiyacı oluşabilir. Workspace sidebar durumu, local draft selection, kullanıcı tarafından değiştirilen uygulama görünüm tercihleri veya karmaşık client workflow bu kategoriye girebilir. State URL'ye veya server'a daha doğal ait değilse Zustand ya da Redux Toolkit gibi store çözümleri değerlendirilebilir. Store'un domain sınırları ve public selector API'leri baştan belirlenmelidir. Shared olması, uygulamadaki bütün client state'in tek store içinde toplanması gerektiği anlamına gelmez.

Form State

Form state, kullanıcının henüz server'a göndermediği input değerlerini, validation sonucunu ve submission durumunu kapsar. Basit form native HTML ve Server Action ile bile yönetilebilir, karmaşık form ise form library veya reducer gerektirebilir. Form verisini global store'a taşımak yalnız farklı route veya component'lar gerçekten aynı draft'ı paylaşacaksa anlamlıdır. Submission sonrası server'ın kabul ettiği değer source of truth hâline gelir ve client draft temizlenebilir. Kurumsal uygulamada form state ile persisted business data arasındaki sınır açık tutulmalıdır.

Workflow State

Checkout, onboarding, approval veya payment gibi çok adımlı süreçlerde state yalnız birkaç boolean değerinden daha fazlasını ifade eder. Hangi adımın hangi şartla diğerine geçtiği, geri dönüşün mümkün olup olmadığı ve failure recovery gibi kurallar workflow state'in parçasıdır. Bu tür yapılar Redux Toolkit ile explicit action modeli üzerinden yönetilebilir veya state machine yaklaşımına taşınabilir. Workflow state'in local component state'e dağılması geçiş kurallarını görünmez hâle getirir. Kurumsal ölçekte kritik akışlar için explicit transition modelini tercih etmek test ve audit kolaylığı sağlar.

Persisted Browser State

Refresh sonrasında korunması gereken fakat server source of truth olmayan state persisted browser state olarak düşünülebilir. Tema tercihi, lokal workspace düzeni veya kullanıcının henüz server'a senkronlanmayan draft ayarları buna örnek olabilir. localStorage, sessionStorage veya IndexedDB kullanılabilir, ancak saklanan şemanın version ve migration planı olmalıdır. Authentication token veya hassas müşteri verisi convenience uğruna browser storage içine yerleştirilmemelidir. Persistence kararı “kaybolmasın” refleksiyle değil güvenlik ve veri ömrü gereksinimiyle verilmelidir.

Derived State

Derived state mevcut state veya server data'dan hesaplanabilen değerdir. Cart total, filtrelenmiş item sayısı veya kullanıcının permission set'inden türetilen `canEdit` gibi sonuçları ayrıca saklamak çoğu zaman iki değerin senkron kalması sorununu doğurur. Selector veya normal fonksiyon üzerinden ihtiyaç anında hesaplama daha güvenli olabilir. Hesap pahalıysa memoization uygulanabilir. Derived state'i saklamamak source of truth sayısını azaltan basit fakat güçlü bir mimari prensiptir.

State Olarak Saklamak Yerine Hesaplanması Gereken Veriler

Bir değer mevcut state'lerden deterministik biçimde üretilebiliyorsa önce onu hesaplamayı düşünmek gerekir. Örneğin `items` ve `selectedIds` zaten mevcutken ayrıca `selectedItems` listesi saklamak senkronizasyon yükü yaratabilir. Redux selector, Zustand selector veya component-level memoization bu değeri ihtiyaç anında üretebilir. Böylece mutation sırasında birden fazla state alanını aynı anda güncelleme zorunluluğu azalır. Kurumsal projede derived state temizliği store boyutunu ve bug yüzeyini ciddi biçimde küçültebilir.

Kurumsal Projeler İçin State Ownership Matrisi

State ownership matrisi, her state parçası için aynı soruları sistematik biçimde sormayı sağlar. Source of truth, yaşam alanı, mutation sahibi, persistence süresi, URL paylaşımı ve request isolation gibi alanlar tablo hâline getirilebilir. Bu yöntem mimari review sırasında “Redux mu Zustand mı?” gibi soyut tartışmaları somut gereksinimlere dönüştürür. Bir değer için verilen cevaplar farklı ekipler arasında ortak terminoloji oluşturur. Next.js'te State Management: Kurumsal Ölçekli Çözümler yaklaşımında bu matris, kütüphane seçiminin önünde duran en yararlı karar aracıdır.

Verinin Source of Truth'ı Kim?

İlk soru her zaman verinin gerçek sahibinin kim olduğudur. Database, browser URL'si, local component, server session veya client workflow store farklı source of truth örnekleridir. Aynı business data hem Server Component hem Redux slice içinde bağımsız olarak tutuluyorsa iki gerçek oluşur. Hangi katmanın authoritative olduğu belli değilse mutation ve invalidation davranışı zamanla tahmin edilemez hâle gelir. State mimarisinde birinci hedef her veri sınıfı için tek authoritative kaynak belirlemektir.

State Nerede Yaşamalı?

State, ona ihtiyaç duyan en küçük ve doğru sahiplik alanında yaşamalıdır. Request state server request scope'ta, URL state URL'de, local interaction component'ta ve cross-feature browser state store içinde tutulabilir. Root-level provider kullanmak teknik olarak kolay görünse de bütün uygulamayı client boundary altına almak veya state ömrünü gereksiz uzatmak gibi yan etkiler oluşturabilir. Route-specific store ilgili route layout'u altında konumlandırılabilir. Yaşam alanı, state'in erişilebilirliğini değil sahipliğini ifade etmelidir.

State'i Kim Değiştirebilir?

State mutation yetkisi verinin kaynağına göre açıkça tanımlanmalıdır. Server-owned veri yalnız backend mutation veya Server Action üzerinden değiştirilirken client store bunun geçici temsilini güncelleyebilir. Redux action'ları domain command gibi tasarlanarak hangi transition'ın kim tarafından yapıldığı görünür tutulabilir. Zustand store'da da random `setState` çağrılarını bütün uygulamaya yaymak yerine action API kullanmak maintainability sağlar. Mutation ownership net olduğunda audit, test ve concurrency senaryoları çok daha kolay yönetilir.

State Ne Kadar Süre Yaşamalı?

Modal state birkaç saniye, route filtreleri navigation boyunca, kullanıcı tercihi aylarca yaşayabilir. State ömrü storage, provider scope ve reset stratejisini belirler. Root singleton store içine konan route-specific state gereğinden uzun yaşayarak yeni sayfaya taşınabilir. Persisted state için expiration veya schema migration gerekebilir. Yaşam süresi baştan tanımlanırsa accidental persistence ve stale UI problemleri önemli ölçüde azalır.

Refresh Sonrası Korunmalı mı?

Refresh sonrasında kaybolması kabul edilebilir state'i persist etmek gereksiz risk oluşturur. Modal açık durumu, transient validation error veya loading flag refresh sonrası korunmamalıdır. Kullanıcı taslak verisi veya UI tercihi ise business ihtiyacına göre saklanabilir. Server-owned data refresh sonrasında zaten yeniden server kaynağından üretilebilir. Persistence kararında kullanıcı deneyimi kadar güvenlik ve schema migration maliyeti de hesaba katılmalıdır.

URL ile Paylaşılabilmeli mi?

Bir kullanıcı mevcut görünümü başka bir kişiye link olarak gönderebilmeli mi sorusu URL state kararını kolaylaştırır. Arama sorgusu, sayfa numarası, sort ve seçili kategori çoğu durumda paylaşılabilir olmalıdır. Bu değerleri global store'da tutmak deep link davranışını kaybettirir. URL aynı zamanda browser history ile doğal undo ve back deneyimi sunar. Shareable state için URL, global store'dan önce değerlendirilmesi gereken birinci sınıf state katmanıdır.

Birden Fazla Kullanıcı Request'i Arasında İzole mi Olmalı?

Authenticated kullanıcıya, tenant'a veya request header'a bağlı her veri request'ler arasında kesin biçimde izole edilmelidir. Server process içinde module-level mutable store kullanmak bu izolasyonu bozabilir. Redux Toolkit ve Zustand'ın Next.js rehberlerinde request bazlı store creation tavsiyesi tam olarak bu riski hedefler. Browser tarafındaki store kullanıcı cihazında tek session içinde global olabilir, fakat server üzerinde aynı yaklaşım güvenli değildir. Kurumsal projede request isolation testleri yalnız performans değil veri güvenliği testi olarak görülmelidir.

State Management Kütüphanesi Kullanmadan Çözülebilecek Problemler

Kurumsal uygulamalarda state kütüphanesi kullanmak normaldir, fakat her state problemi için library eklemek gereksizdir. React'in kendi hook'ları, Context, URL, Server Components ve Server Actions geniş bir problem alanını zaten kapsar. Global store ihtiyacını azaltmak component'ların bağımsızlığını ve server/client boundary kontrolünü güçlendirir. Kütüphanesiz çözüm “basit proje” anlamına gelmez, doğru ownership alanını seçmek anlamına gelir. Store eklemeden önce platformun sunduğu primitive'lerin problemi gerçekten karşılayıp karşılamadığı mutlaka değerlendirilmelidir.

useState

`useState` tek component veya dar subtree için en düşük maliyetli state aracıdır. Modal, toggle, selected row veya geçici input state'i gibi basit etkileşimler için global store ihtiyacını ortadan kaldırır. Component unmount olduğunda state'in doğal olarak temizlenmesi bazı route-specific senaryolarda avantajdır. State paylaşımı genişledikçe prop drilling başlıyorsa Context veya store değerlendirilebilir. `useState` küçük olduğu için değil, doğru scope'u doğal biçimde ifade ettiği için kurumsal mimaride de önemli bir araçtır.

useReducer

`useReducer` bir component veya feature içinde state transition'ları action tabanlı biçimde görünür kılmak için kullanışlıdır. Birden fazla field'ın birlikte değiştiği form veya local workflow senaryosunda `useState` zincirinden daha okunabilir olabilir. Reducer pure tutulursa kolay unit test edilir. State farklı route veya feature'lar arasında paylaşılmıyorsa Redux Toolkit eklemek yerine local reducer yeterli olabilir. Reducer modeli büyüyüp cross-feature business state'e dönüştüğünde daha merkezi store düşünmek mantıklı hâle gelir.

React Context

React Context theme, locale ve nadiren değişen configuration gibi küçük shared state için güçlü bir built-in araçtır. Context value sık değişiyorsa bütün consumer'ların render davranışı dikkatle incelenmelidir. Provider mümkün olduğunca dar subtree içinde tutulmalıdır. Context içine server response, onlarca action ve büyük mutable object eklemek onu görünmez global store'a dönüştürebilir. Stable configuration paylaşımı için Context yeterliyken karmaşık business state için explicit store daha sağlıklı olabilir.

searchParams ile URL State

`searchParams` arama, filtre, sort ve pagination gibi navigation ile ilişkili state'i taşımak için doğal araçtır. Server Component mevcut query parametrelerini okuyup veriyi doğrudan buna göre fetch edebilir. Client filtre component'ı URL'yi güncellediğinde back button ve bookmark davranışı otomatik olarak korunur. Redux veya Zustand ile ikinci bir filtre state'i oluşturmak senkronizasyon zorunluluğu getirir. Özellikle admin dashboard ve catalog sayfalarında URL state global store boyutunu ciddi biçimde azaltabilir.

Route Parameters

Tenant slug, product id veya workspace adı route parameter olarak zaten navigation state'in parçasıdır. Bu değerleri ayrıca global store'a kopyalamak gereksiz olabilir. Server Component parametreyi kullanarak ilgili veriyi fetch edebilir ve route değişiminde framework yeni state bağlamını doğal olarak oluşturur. Client tarafında route hook'ları üzerinden mevcut parametre okunabilir. Route'a ait kimliği store'da tutmak stale route state sorunlarına açık kapı bırakır.

Form State

Basit form state'i native input, `FormData` ve Server Action ile kütüphanesiz yönetilebilir. Client-side enhancement gerekiyorsa yalnız ilgili validation veya pending state eklenebilir. Form değerlerini global store'da saklamak yalnız farklı sayfalar arasında gerçek draft paylaşımı varsa anlamlıdır. Submit edilen data server tarafından doğrulanmalı ve authoritative sonuç server'da oluşmalıdır. Form state'in ayrı kategori olarak ele alınması global store'un gereksiz büyümesini engeller.

Server Components ile Server State

Server Component server-owned veriyi client cache library olmadan doğrudan okuyabilir. Product detail, account overview veya CMS içeriği request veya cache stratejisine göre server'dan render edilebilir. Client'ın yalnız etkileşim gereken parçasına gerekli minimum data gönderilir. Bu yaklaşım browser tarafında server response kopyaları tutma ihtiyacını azaltır. Server state'in kaynağa yakın tutulması güvenlik ve data freshness modelini de daha anlaşılır hâle getirir.

Server Actions ile Mutation

Server Actions form veya client interaction'dan server mutation çalıştırmayı kolaylaştırabilir. Mutation sonunda `revalidatePath`, tag invalidation veya redirect gibi adımlarla UI tekrar server gerçeğine bağlanabilir. Böylece basit CRUD işlemlerinde ayrı client API layer ve global mutation state gerekmeyebilir. Yetkilendirme ve input validation Server Action içinde yine zorunludur. Server Action kullanımı client cache library ihtiyacını tamamen ortadan kaldırmaz, ancak server-first uygulamalarda birçok mutation akışını sadeleştirebilir.

URL'yi Bir State Management Katmanı Olarak Kullanmak

URL çoğu ekip tarafından navigation çıktısı olarak görülür, ancak kurumsal frontend mimarisinde güçlü bir state katmanıdır. Kullanıcının görünümünü paylaşılabilir, bookmark edilebilir ve browser history ile geri alınabilir hâle getirir. Next.js App Router, route ve query parametrelerini Server Components ile doğrudan ilişkilendirebildiği için URL state özellikle değerlidir. Store ve URL arasında çift yönlü senkronizasyon kurmak yerine mümkün olduğunda URL'yi tek source of truth yapmak daha sağlamdır. Next.js App Router ile global state ve server state yönetimi nasıl yapılır sorusunun önemli cevaplarından biri, aslında global store'a taşınmaması gereken navigation state'i URL'de bırakmaktır.

Filtreler

Category, status, date range ve team gibi filtreler çoğu zaman URL query parametresi için uygundur. Kullanıcı filtrelenmiş görünümü başka birine gönderebilir ve aynı sonuç tekrar açılabilir. Server Component filtreleri okuyup backend sorgusunu buna göre oluşturabilir. Global store kullanılmadığı için route refresh sonrasında state kaybolmaz. Çok sayıda filtre varsa parametre formatı ve default değerler açık standarda bağlanmalıdır.

Arama

Search query URL'de tutulduğunda kullanıcı arama sonucunu bookmark edebilir. Debounce ile URL update yapılabilir ve server data yeni query üzerinden getirilebilir. Search input local draft tutup submit veya debounce sonrası URL'ye yazabilir. Bu separation, her keypress'in global store action'ına dönüşmesini engeller. Analytics de URL query parametresinden search intent'i daha kolay ilişkilendirebilir.

Pagination

Pagination state URL için klasik kullanım alanıdır. `page=3` veya cursor tabanlı parametre kullanıcıya doğrudan belirli sonuç sayfasını açma imkânı verir. Browser back davranışı doğru çalışır. Global store içindeki page değeri refresh ile kaybolabileceği için daha zayıf bir source of truth olur. Server ve client pagination modeli backend contract'ıyla uyumlu tasarlanmalıdır.

Sorting

Sort field ve direction URL'de taşındığında görünüm paylaşılabilir hâle gelir. Default sort parametresi URL'de olmayabilir ve server tarafında belirlenebilir. Unsupported sort değeri validation ile güvenli default'a çevrilmelidir. Store içinde ayrıca sort state tutmak duplicate source oluşturabilir. Data table gibi yoğun kurumsal ekranlarda URL sort yaklaşımı test ve debugging sürecini de kolaylaştırır.

Aktif Tab

Aktif tab, tab değişikliği içerik veya route anlamını değiştiriyorsa URL state olabilir. Kullanıcı belirli tab'a doğrudan link gönderebilir. Sadece küçük visual preference olan tab ise local state yeterli olabilir. Her tab state'ini URL'ye koymak da gereksiz olabilir. Karar tab'ın navigation açısından kalıcı bir anlam taşıyıp taşımadığına göre verilmelidir.

Shareable ve Bookmarkable State

State'in shareable olması support, collaboration ve kullanıcı deneyimi için güçlü avantajdır. Kullanıcı “şu filtreyi açıp sayfa üçe git” diye tarif etmek yerine link gönderebilir. Support ekibi aynı ekran state'ini doğrudan tekrar üretir. QA bug report'ları belirli URL ile daha kolay çoğaltılabilir. Bu faydalar global store yerine URL kullanımının yalnız teknik değil operasyonel kazanç da sağladığını gösterir.

URL State Ne Zaman Global Store'dan Daha İyidir?

State navigation ile ilişkiliyse, kullanıcı tarafından paylaşılacaksa ve refresh sonrasında korunması isteniyorsa URL genellikle daha iyi seçimdir. Global store bu özellikleri kendiliğinden sağlamaz ve persistence eklemek gerekir. URL ayrıca browser history davranışını ücretsiz olarak getirir. Sensitive veya çok büyük veri URL'ye konmamalıdır. Basit karar kuralı olarak “bu ekran state'i link olarak anlamlı mı?” sorusu çoğu durumda doğru yönü gösterir.

Server State'i Global Client Store'a Koymalı mısınız?

Çoğu durumda server-owned data'yı doğrudan global client store'un sahibi yapmak iyi başlangıç değildir. API response'u Redux veya Zustand içine kopyaladığınız anda backend ve store arasında iki source of truth ortaya çıkabilir. Mutation sonrası hangi verinin authoritative olduğu, cache'in ne zaman temizleneceği ve navigation sırasında eski data'nın ne kadar yaşayacağı zorlaşır. Server Components veya browser server-cache library'leri bu problemi daha doğru katmanlarda çözebilir. Global client store yalnız server verisine dayalı geçici interaction state'ini taşımak için kullanılabilir, ancak kalıcı business gerçeğin sahibi olmamalıdır.

Server State ile Client State Arasındaki Fark

Server state kullanıcı dışında da değişebilen ve gerçek sahibi backend olan veridir. Client state ise browser session içinde kullanıcı etkileşimleriyle değişen UI veya workflow bilgisidir. Product price başka bir kullanıcı veya admin tarafından server'da değişebilir, modal durumu ise yalnız mevcut browser instance'ına aittir. İki state türünün freshness ve concurrency ihtiyaçları farklıdır. Aynı store modeliyle ikisini yönetmek bu farkı gizler ve cache davranışını zorlaştırır.

Duplicate Source of Truth Problemi

Server response store'a kopyalandığında server cache bir değer, browser store başka değer taşıyabilir. Mutation sonrası store güncellenip server cache unutulursa route refresh eski data gösterebilir. Tersi durumda server fresh data üretirken store stale kalabilir. Bu fark özellikle optimistic update ve multi-tab senaryolarında daha görünür olur. Source of truth sayısını azaltmak state management güvenilirliğinin temel hedeflerinden biridir.

Client Store'a API Response Kopyalamanın Riskleri

API response'u global store'a kopyalamak loading, error, stale time, retry ve invalidation gibi server-cache problemlerini de sizin manuel çözmeniz gerektiği anlamına gelir. Normalized entity store bazı karmaşık client workflow'larda gerekli olabilir, ancak sıradan query data için gereğinden fazla bakım üretir. React Query veya RTK Query bu alan için özel cache davranışları sunar. Server Components ise client cache gerekmeyen ekranlarda veriyi server tarafında tutar. Store'a kopyalama kararı convenience değil gerçek business manipulation ihtiyacıyla gerekçelendirilmelidir.

Server Components ile Data Ownership

Server Component veriyi doğrudan backend kaynağından veya server cache üzerinden okuyabilir. Component'ın ihtiyacı olan veriyi browser'a yalnız render sonucu veya props olarak gönderir. Client store'un tüm record set'i sahiplenmesi gerekmez. Mutation sonrasında server path veya tag revalidate edilerek yeni authoritative görünüm üretilebilir. Bu yaklaşım özellikle read-heavy kurumsal dashboard ve detail ekranlarında state mimarisini sadeleştirir.

Browser Tarafında Server Cache Ne Zaman Gereklidir?

Live dashboard, polling, background refetch, optimistic update veya offline benzeri browser davranışları gerektiğinde client-side server cache değerli olur. TanStack Query bu tür ihtiyaçlarda loading, stale, retry ve invalidation modelini standartlaştırabilir. Server Component initial data'yı prefetch ederek HydrationBoundary üzerinden client cache'e aktarabilir. Böylece ilk render server'dan gelirken daha sonraki canlı etkileşim browser cache üzerinden devam eder. Server cache library kullanımı gerçek interaction gereksinimine bağlı olmalı, her server query için varsayılan hâle gelmemelidir.

Next.js Server Components ile State Management

Server Components state management tartışmasını browser store merkezinden çıkarıp server-owned data merkezine taşır. Birçok sayfa için veriyi server'da okuyup HTML ve RSC payload üzerinden client'a ulaştırmak yeterlidir. Client'ın değiştirilebilir state'e ihtiyacı olduğunda küçük Client Component boundary açılır. Request state ve secrets server tarafında kalır. Bu server-first model, kurumsal uygulamalarda state'in güvenlik ve ownership sınırlarını daha açık kurmaya yardımcı olur.

Server-First Yaklaşım

Server-first yaklaşım her şeyi server'da yapmak anlamına gelmez. Önce server'a doğal ait veriyi orada tutar, yalnız interactivity gereken alanı client'a taşır. Böylece browser bundle ve global store büyümesi kontrol altında kalır. Client state gerçek browser ihtiyacı için ayrılır. Bu yaklaşım state kütüphanesini tamamen ortadan kaldırmasa da kullanım alanını daha net ve küçük hâle getirir.

Server Component'ta Data Fetching

Server Component backend API veya database'e kaynağa yakın noktadan erişebilir. Secret credential browser'a gönderilmez. Fetch sonucu route veya data cache stratejisine göre tekrar kullanılabilir. Component async çalışarak veriyi render öncesi alabilir. Read-heavy enterprise ekranlarda bu model client `useEffect` fetch zincirlerini önemli ölçüde azaltabilir.

Server'dan Client Component'a Initial State Aktarmak

Bazen Client Component ilk açılışta server'dan hesaplanan değerle başlamalıdır. Server Component bu veriyi prop olarak Client Component'a aktarabilir. Client store oluşturulurken aynı initial value ile initialize edilirse hydration tutarlılığı korunur. Sonraki değişiklikler browser-owned state olarak store içinde devam edebilir. Bu pattern server snapshot ile client mutable state arasındaki geçişi açık hâle getirir.

Serializable Props Kısıtı

Server Component'tan Client Component'a geçen props React tarafından taşınabilir biçimde serializable olmalıdır. Function, açık database connection veya client'ta yeniden oluşturulamayacak runtime object'ler boundary üzerinden doğrudan geçirilmemelidir. Domain entity'leri sade DTO biçimine dönüştürmek çoğu zaman daha güvenlidir. Date veya özel type davranışları kullanılan serialization modeline göre açıkça ele alınmalıdır. Boundary contract'ını sade tutmak client/server coupling'i azaltır.

Request-Specific State

Request-specific state her kullanıcı isteğinde farklı olabilecek server bağlamıdır. Cookie, header, session veya tenant gibi değerler aynı process içinde başka request'lerle paylaşılmamalıdır. Server Component bu bilgiyi request API'lerinden okuyup ilgili render'a uygular. Global mutable store'a yazmak yanlış isolation modeli oluşturur. Enterprise uygulamalarda request-specific context'i açık server katmanında tutmak güvenlik açısından kritik öneme sahiptir.

Cookies

Cookie session id, locale veya kullanıcı tercihi gibi request bilgisini taşıyabilir. Server tarafında okunarak ilgili render davranışı belirlenebilir. Hassas değer HttpOnly olduğunda browser JavaScript tarafından okunmaması güvenlik avantajı sağlar. Cookie değerini client global store'a kopyalamak her zaman gerekli değildir. Mutation sonrasında cookie değişiyorsa yeni server render davranışıyla uyumlu cache stratejisi düşünülmelidir.

Headers

Request header region, proxy bilgisi veya internal request metadata taşıyabilir. Server Component veya server utility bu bilgiyi request kapsamında okuyabilir. Header değerlerinin tamamını client'a expose etmek güvenli değildir. Authentication veya internal infrastructure bilgisi server sınırında kalmalıdır. State architecture header data'yı process-global değişkenlere dönüştürmemelidir.

Session

Session'ın authoritative kaynağı server tarafında olmalıdır. Client user bilgisini yalnız UI snapshot'ı olarak kullanabilir. Session expiration veya permission değişikliği server kontrolüyle doğrulanır. Redux veya Zustand içindeki `isAuthenticated` boolean tek başına gerçek güvenlik kararı değildir. Server-rendered auth state ve client cache reset politikası birlikte tasarlanmalıdır.

Tenant Bilgisi

Multi-tenant sistemde tenant id request state'in en hassas parçalarından biridir. Route, session veya domain üzerinden belirlenebilir. Server query ve cache key'leri tenant bilgisini içermelidir. Singleton store içinde tenant context paylaşılması cross-tenant veri riskine yol açabilir. Her request ve cache katmanında tenant isolation açıkça test edilmelidir.

Next.js Cache Bir State Management Mekanizması mıdır?

Next.js cache, client interaction state'ini yöneten global store değildir, ancak server-owned data'nın freshness ve tekrar kullanım davranışını belirlediği için state architecture'ın önemli parçasıdır. Cache'in görevi authoritative verinin geçici temsilini belirli politika altında yeniden kullanmaktır. Kullanıcı modal açıp kapatma veya client workflow state'ini burada yönetmez. Mutation sonrasında `revalidatePath`, tag invalidation veya uygun refresh modeli kullanılarak server görünümü güncellenir. Cache'i state store ile karıştırmadan ayrı ownership ve invalidation katmanı olarak düşünmek daha doğru bir modeldir.

Server Cache ile Client Store Arasındaki Fark

Server cache backend'den alınan verinin yeniden kullanımını optimize eder. Client store browser etkileşimi ve mutable client-owned state'i taşır. Cache stale olabilir ve yeniden doğrulanabilir, client state ise çoğu zaman kullanıcı aksiyonlarıyla hemen güncellenir. Cache process veya deployment stratejisine göre server tarafında yaşarken client store kullanıcı browser'ında yaşar. İki katmanın yaşam süresi ve güvenlik sınırı birbirinden farklıdır.

Cache Ownership

Her cache entry'nin hangi domain verisine ait olduğu ve hangi mutation tarafından invalidatedileceği bilinmelidir. Genel “her şeyi beş dakika cache'le” yaklaşımı business freshness ihtiyacını karşılamayabilir. Product catalog ile payment status aynı freshness politikasına sahip değildir. Tag isimleri domain odaklı tasarlanabilir. Cache owner belli olduğunda incident sırasında stale data'nın hangi ekip tarafından yönetileceği de açık olur.

Freshness Politikası

Freshness business requirement'tır ve teknik TTL değeri bunun sonucudur. Marketing content saatlerce stale kalabilirken account balance saniyeler içinde güncel olmalıdır. Cache süresi kullanıcı beklentisine göre belirlenir. Mutation gerçekleştiğinde TTL beklemek yerine on-demand invalidation gerekebilir. Freshness policy dokümante edilmeden cache davranışı farklı ekiplerde tutarsızlaşır.

revalidateTag

Tag tabanlı invalidation aynı domain datasını kullanan farklı path'leri birlikte hedeflemek için kullanışlıdır. Product verisi birden fazla sayfada kullanılıyorsa ilgili fetch'ler ortak tag taşıyabilir. Mutation bu tag'i stale hâle getirerek sonraki erişimlerde fresh data alınmasını sağlar. Tag ismi domain contract'ın parçası gibi standardize edilmelidir. Çok geniş tag kullanmak gereksiz cache invalidation ve yeniden fetch maliyeti oluşturabilir.

revalidatePath

`revalidatePath` belirli page veya layout path'inin cache davranışını yenilemek için kullanılabilir. Mutation sonrası kullanıcı aynı path'te güncel görünüm görmek istiyorsa güçlü bir araçtır. Ancak aynı data başka path'lerde de kullanılıyorsa yalnız path invalidation yeterli olmayabilir. Bu durumda data tag politikasıyla birlikte düşünmek gerekir. Path ve data invalidation arasındaki fark architecture guideline içinde açıkça anlatılmalıdır.

Mutation Sonrası Invalidation

Mutation başarılı olduğunda yalnız database'i güncellemek kullanıcıya fresh UI garanti etmez. Server cache ve client cache ayrı ayrı stale kalabilir. Mutation handler hangi server tag veya path'i, hangi TanStack Query key'ini invalidatedeceğini bilmelidir. Kurumsal projede bu davranışı ad hoc component koduna bırakmak unutulmuş invalidation hatalarını artırır. Domain mutation policy içinde server ve client cache etkileri birlikte tanımlanmalıdır.

Stale-While-Revalidate Yaklaşımı

Stale-while-revalidate yaklaşımı kullanıcıya mevcut cached data'yı hızlı sunarken arka planda yeni veri hazırlamayı hedefler. Read-heavy ve küçük freshness toleransı olan sayfalarda iyi kullanıcı deneyimi sağlayabilir. Kritik finansal veya authorization data için aynı politika uygun olmayabilir. UI stale olabilecek bilgiyi kullanıcıya yanlış kesinlikte sunmamalıdır. Cache strategy her domain'in veri toleransına göre seçilmelidir.

Zustand ile Next.js State Management

Zustand küçük API yüzeyi ve selector tabanlı subscription modeliyle browser-owned shared state için kullanışlı bir seçenektir. Ancak Next.js App Router'da klasik SPA'deki module-level global store alışkanlığını doğrudan taşımak güvenli değildir. Request isolation, hydration ve server/client boundary kuralları doğru uygulanmalıdır. Zustand özellikle UI workspace state, client draft veya geniş olmayan cross-component interaction state'inde iyi denge sağlayabilir. Next.js kurumsal uygulamalarda Zustand Redux Toolkit ve TanStack Query mimarisi kurarken Zustand'ın rolü server cache değil shared browser state olarak açık tutulmalıdır.

Zustand Ne Zaman Mantıklıdır?

Birden fazla Client Component aynı mutable browser state'i kullanıyor ve Redux kadar geniş convention ihtiyacı bulunmuyorsa Zustand mantıklı olabilir. Sidebar state, editor selection, workspace layout veya local cart draft gibi örnekler uygundur. State server source of truth ise önce Server Component veya TanStack Query değerlendirilmelidir. Store API küçük tutulmalı ve action ile selector'lar domain sınırına göre düzenlenmelidir. Ekip sayısı büyüdükçe convention'ları dokümante etmek library'nin sade API'sinden daha önemli hâle gelir.

Shared Browser-Owned State

Zustand'ın en doğal alanı browser'ın sahip olduğu ve birkaç component arasında paylaşılan mutable state'tir. Örneğin kanban görünümünde seçili card, client-only workspace düzeni veya local draft state farklı component'lar tarafından tüketilebilir. Bu state URL'ye ait değilse ve server tarafından authoritative olarak tutulmuyorsa store iyi bir abstraction sağlar. Persistence gerekirse ayrıca middleware uygulanabilir. Shared browser state ile server response cache'i aynı store içinde karıştırmamak gerekir.

Store ve Action Tasarımı

Store state shape ve action API'sini birlikte tanımlamak değişikliklerin nereden geldiğini görünür yapar. Component'ların doğrudan `setState` çağırması yerine `openSidebar`, `selectWorkspace` veya `resetDraft` gibi anlamlı action'lar tercih edilebilir. Bu yaklaşım ileride logging ve test eklemeyi kolaylaştırır. Büyük store yerine feature store veya slice pattern değerlendirilebilir. Public action isimleri UI event'inden çok domain niyetini ifade ettiğinde refactoring daha rahat olur.

Selector Kullanımı

Component store'un tamamına subscribe olmak yerine yalnız ihtiyaç duyduğu alanı selector ile seçmelidir. Bu yaklaşım gereksiz re-render sayısını azaltır. Bir component yalnız `sidebarOpen` kullanıyorsa bütün workspace state object'ini okumamalıdır. Composite selector kullanıldığında referential equality ve shallow comparison dikkate alınabilir. Selector'lar component'ı internal store shape'ten uzaklaştıracak domain API rolü de üstlenebilir.

Gereksiz Re-render'ları Önleme

Zustand performans avantajı doğru subscription granularity kullanıldığında ortaya çıkar. Store'un tamamını döndüren selector her değişiklikte component'ı etkileyebilir. Küçük selector'lar ve gerektiğinde shallow equality kullanılmalıdır. Büyük object'leri her render'da yeniden üreten selector'lar referans değişimi nedeniyle ek render oluşturabilir. Performance problemi varsayımla değil React profiler ve gerçek interaction ölçümüyle doğrulanmalıdır.

Zustand Middleware

Zustand middleware persistence, devtools entegrasyonu veya state update ergonomisi için store'a ek davranış kazandırır. Her middleware ayrı maliyet ve davranış getirir. Kurumsal projede middleware stack standardize edilmezse farklı store'lar farklı persistence ve debugging davranışına sahip olabilir. Özellikle `persist` kullanılan state için schema versioning zorunlu düşünülmelidir. Middleware yalnız gerçekten gerekli capability için eklenmelidir.

persist

`persist` middleware state'i localStorage veya başka storage backend'ine yazmayı kolaylaştırır. Ancak browser storage'dan okunan verinin runtime type açısından güvenilir olduğu varsayılmamalıdır. Version ve migrate mekanizması eski schema'yı yeni store shape'e taşımak için kullanılabilir. SSR sırasında browser storage server tarafında mevcut olmadığı için hydration stratejisi dikkatle kurulmalıdır. Hassas token ve kullanıcı verisi persistence convenience uğruna bu katmana konmamalıdır.

devtools

`devtools` middleware development sırasında action ve state değişikliklerini incelemeyi kolaylaştırabilir. Action isimlerinin anlamlı olması debugging deneyimini doğrudan iyileştirir. Production build'de gerekli olup olmadığı ekip politikasına göre belirlenebilir. Sensitive state development loglarında bile dikkatle ele alınmalıdır. DevTools desteği küçük store'larda bile state transition sorunlarını hızlı bulmak için faydalıdır.

immer

`immer` nested immutable update yazımını sadeleştirebilir. Özellikle derin client workflow state'inde spread zincirlerini azaltır. Buna rağmen store shape'in gereğinden derin tasarlanması mimari problemi gizleyebilir. Update semantics ekip tarafından anlaşılmalı ve performans kritik alanlarda gereksiz büyük object kopyaları ölçülmelidir. Middleware ergonomi sağlar, state modelini otomatik olarak iyi hâle getirmez.

subscribeWithSelector

`subscribeWithSelector` belirli state parçalarına React dışından veya düşük seviyeli subscription ile tepki vermeyi sağlar. Analytics, storage sync veya özel event bridge gibi senaryolarda kullanılabilir. Subscription lifecycle doğru temizlenmelidir. Business logic'i component dışı observer zincirlerine dağıtmak debugging sürecini zorlaştırabilir. Bu nedenle use case açık ve sınırlı tutulmalıdır.

Next.js'te Zustand Kullanırken Request Isolation

Next.js server aynı anda birçok request işleyebildiği için server tarafında process-global Zustand store oluşturmak risklidir. Bir request'in initialization verisi başka request tarafından görülebilecek paylaşımlı mutable state'e dönüşebilir. Resmî Zustand Next.js rehberi store'un request başına oluşturulmasını ve RSC'lerin store'u okumamasını önerir. Client Provider içinde store factory kullanmak scoped ve re-render güvenli bir çözüm sağlar. Request isolation, Zustand kullanımında performans detayı değil veri güvenliği sınırıdır.

Neden Module-Level Global Store Risklidir?

SPA ortamında module-level store browser tab'ına özgü global state gibi davranabilir. Next.js server rendering sırasında aynı module instance birden fazla kullanıcı request'i tarafından kullanılabilir. Store içinde request-specific data initialize edilirse veri kullanıcılar arasında karışabilir. Bu risk development'ta düşük concurrency nedeniyle fark edilmeyebilir. Production load altında isolation testi yapılmadıkça güvenli varsayılmamalıdır.

Concurrent Request Problemi

İki request aynı anda aynı store instance'ı değiştirdiğinde ilk request'in state'i ikinci request render'ına sızabilir. Tenant veya user data taşıyan store'da bunun etkisi ciddi olabilir. Race condition deterministik olmadığı için test etmek zorlaşır. Request başına ayrı store instance oluşturmak problemi kökten azaltır. Server process global değişkenleri yalnız immutable configuration için kullanmak daha güvenli bir ilkedir.

Request Başına Store Oluşturmak

Store factory her render/request bağlamı için yeni store instance üretir. Initial state server'dan alınan serializable props ile initialize edilebilir. Client Provider bu instance'ı component lifecycle boyunca korur. Başka request farklı instance kullandığı için veri isolation sağlanır. Store creation pattern organization template'ine eklenirse ekiplerin singleton hatası yapma riski azalır.

Store Factory Pattern

Factory function store configuration'ını tek yerde tutar fakat instance'ı çağrı anında üretir. Testler de her test case için yeni store oluşturarak state leakage sorununu önler. Initial state parametre olarak verilebilir. Middleware ve action setup factory içinde standardize edilir. Bu pattern hem Zustand hem Redux Toolkit request isolation yaklaşımında benzer mimari düşünce sunar.

Context Provider ile Scoped Zustand Store

Zustand vanilla store instance'ı React Context üzerinden belirli subtree'ye sağlanabilir. Provider Client Component olur ve store'u yalnız bir kez oluşturur. Route-specific state gerekiyorsa provider ilgili route layout veya page altında konumlandırılabilir. Böylece state başka route'lara gereksiz taşınmaz. Context burada state manager olarak değil store instance scope'unu dağıtan dependency injection katmanı olarak kullanılır.

Server Components Neden Zustand Store'dan Okumamalıdır?

Server Components request ve cache semantiğiyle çalışırken Zustand store mutable client-oriented state modelidir. RSC'nin global store okuması request isolation ve cache tutarlılığı sorunları doğurabilir. Ayrıca context ve client hook'ları Server Components içinde kullanılamaz. Server data doğrudan backend veya server cache kaynağından okunmalıdır. Gerekli initial snapshot Client Component'a prop olarak aktarılabilir.

Zustand ve SSR/Hydration Problemleri

SSR ve hydration sırasında server tarafından üretilen ilk UI ile client'ın ilk render'ı uyumlu olmalıdır. Zustand store server'da farklı, browser'da localStorage üzerinden farklı değerle başlarsa hydration mismatch oluşabilir. Persisted store kullanımı bu nedenle bilinçli initialization ve rehydration stratejisi gerektirir. Browser-only state ilk render'da deterministic default kullanabilir ve hydration sonrasında güncellenebilir. Kurumsal projede hydration testi gerçek production state senaryolarını içermelidir.

Server ve Client Initial State'in Aynı Olması

Server render'da sidebar kapalı, client ilk render'da açık görünürse HTML uyumsuzluğu oluşabilir. Initial state iki environment için aynı kaynaktan üretilmelidir. Server'dan prop ile client provider'a aktarılan state güvenli yöntemlerden biridir. Browser storage yalnız hydration sonrasında override edilebilir. İlk render deterministik olduğunda flicker ve hydration warning riski azalır.

localStorage Kaynaklı Hydration Mismatch

Server `localStorage` erişemez ve default değerle render üretir. Browser ise daha önce saklanan değeri hemen okuyup farklı markup üretirse mismatch oluşabilir. Storage okumasını client hydration sonrasına ertelemek veya loading gate kullanmak gerekebilir. Kritik layout state'i cookie üzerinden server'a da taşımak başka bir seçenek olabilir. Hangi yaklaşımın daha iyi olduğu UX ve security ihtiyacına bağlıdır.

Persisted Store Hydration

Persisted state storage'dan okunduğunda eski schema veya bozuk data ile karşılaşılabilir. Store hydration tamamlandı mı bilgisinin UI tarafından bilinmesi bazı ekranlarda önemlidir. Default state ve persisted state transition'ı kullanıcıya görünür flicker yaratmamalıdır. Version migration uygulanmalıdır. Persistence katmanı application startup flow'unun kontrollü parçası olarak tasarlanmalıdır.

Browser-Only State'in Güvenli Başlatılması

Viewport, localStorage veya browser permission gibi state server'da bilinmez. İlk render'da neutral ve deterministic değer kullanılabilir. Client mount sonrasında gerçek browser state okunarak component güncellenir. Bu değişim layout shift yaratıyorsa placeholder veya CSS yaklaşımı değerlendirilmelidir. Browser-only state'in server render'ı taklit etmeye zorlanması yerine boundary açıkça kabul edilmelidir.

Hydration Testleri

Unit test store logic'ini doğrulasa da hydration problemini tek başına yakalamaz. Server-rendered HTML ile client hydration aynı initial state üzerinden e2e veya integration testte çalıştırılmalıdır. Persisted storage dolu ve boş senaryolar ayrı test edilmelidir. Route navigation sırasında store reset davranışı da gözlemlenmelidir. Hydration warning production log veya telemetry içinde görünür hâle getirilebilir.

Redux Toolkit ile Kurumsal Next.js State Management

Redux Toolkit büyük ekiplerde convention, explicit action modeli, middleware ve güçlü debugging ihtiyacı olduğunda hâlâ anlamlı bir seçenektir. Özellikle karmaşık client-side business workflow'larda state transition'larını standartlaştırır. App Router kullanırken klasik singleton store yaklaşımı yerine request-safe factory ve Client Provider pattern uygulanmalıdır. RSC'ler Redux store'u okumamalı veya yazmamalıdır. Redux Toolkit'in değeri yalnız state depolamak değil, büyük ekipte değişiklik modelini ortaklaştırmak ve denetlenebilir hâle getirmektir.

Redux Toolkit Ne Zaman Tercih Edilmelidir?

Çok sayıda ekip aynı client workflow üzerinde çalışıyor ve action/reducer convention'ına ihtiyaç duyuyorsa Redux Toolkit güçlü adaydır. Checkout, complex editor, entitlement configuration veya birçok domain'i birleştiren browser workflow örnek olabilir. Server query data'yı otomatik olarak Redux slice'a kopyalamak gerekmez. RTK Query veya TanStack Query ayrı server-cache katmanı olarak kullanılabilir. Redux seçimi store büyüklüğüne değil business transition karmaşıklığı ve ekip standardizasyonu ihtiyacına dayanmalıdır.

Büyük Ekiplerde Convention'ın Değeri

Onlarca developer'ın state update'i aynı kalıpla yazması code review ve onboarding süresini azaltır. Slice, action, selector ve middleware yapısı ortak vocabulary oluşturur. Yeni ekip üyesi farklı feature'larda benzer pattern görür. Zustand gibi daha esnek araçlarda bu convention'ı ekibin kendisi oluşturması gerekir. Redux Toolkit'in daha yapılandırılmış yaklaşımı bazı büyük organizasyonlarda bu nedenle maliyet değil avantajdır.

configureStore

`configureStore` reducer, middleware ve DevTools entegrasyonunu ortak noktada kurar. Next.js'te doğrudan singleton export etmek yerine `makeStore` factory içinde çağrılması request safety sağlar. Root state ve dispatch type factory dönüşünden türetilebilir. Testlerde aynı factory yeni temiz store üretir. Store configuration domain reducer'larıyla ölçeklendikçe modüler tutulmalıdır.

createSlice

`createSlice` state, reducer logic ve action creator'ları feature çevresinde birleştirir. Domain-oriented slice yapısı büyük projede dosya organizasyonunu kolaylaştırır. Action isimleri UI event yerine business intent'i yansıtabilir. Slice yalnız mutable client state'i taşımalıdır. Server-owned data'yı sırf erişim kolaylığı için slice'a kopyalamak Redux kullanım alanını gereksiz büyütür.

Typed Hooks

Typed dispatch ve selector hook'ları store type bilgisini component seviyesinde standartlaştırır. Her component'ın generic type yazmasına gerek kalmaz. Refactoring sırasında TypeScript store shape değişikliklerini daha erken yakalar. Type-safe frontend yaklaşımını daha geniş ele almak isteyen ekipler https://www.diyarbakiryazilim.com.tr/posts/typescript-ile-frontend-projelerinde-hata-oranini-dusurmek adresindeki TypeScript odaklı içeriği de inceleyebilir. Typed hook kullanımı runtime correctness garantisi olmasa da geniş codebase'de hatalı state erişimini azaltan önemli bir compile-time kontrol sağlar.

Middleware

Redux middleware action ile reducer arasındaki akışta logging, async coordination veya policy uygulamak için kullanılabilir. Her feature kendi custom side effect altyapısını yazmamalıdır. Ancak middleware içine business logic'i görünmez şekilde dağıtmak debugging'i zorlaştırabilir. Modern Redux uygulamalarında side effect ihtiyacı use case'e göre listener middleware veya query layer ile çözülebilir. Middleware stack organization standardı olarak merkezi yönetilmelidir.

Redux DevTools

Redux DevTools action sırasını ve state değişimini gözlemlemek için güçlü debugging imkânı sağlar. Karmaşık workflow bug'larında hangi action'ın yanlış transition ürettiğini görmek kolaylaşır. Sensitive data development araçlarına taşınırken güvenlik politikası düşünülmelidir. Production telemetry ile aynı action taxonomy kullanılması incident analizini destekler. DevTools tek başına iyi architecture oluşturmaz, ancak explicit action modelinin değerini artırır.

Audit Edilebilir State Transition'ları

Regüle veya kritik business workflow'larda state'in neden değiştiğini bilmek önemlidir. Redux action'ları transition intent'ini açıkça ifade edebilir. Action logging veya domain event mapping ile kullanıcı akışı yeniden oluşturulabilir. Her UI keystroke'u audit event yapmak gerekli değildir. Audit edilmesi gereken business transition'lar ayrı action ve telemetry standardıyla tanımlanmalıdır.

Next.js App Router'da Redux Store Nasıl Oluşturulmalıdır?

App Router'da Redux setup'ın en önemli farkı store instance'ının server üzerinde global singleton olmamasıdır. `makeStore` factory yeni store üretir ve Client Provider ilgili request/render context'inde instance'ı oluşturur. Server'dan gelen initial data provider üzerinden initialize edilebilir. Route-specific state kullanılıyorsa provider scope veya reset policy ayrıca tasarlanmalıdır. RSC Redux store'a doğrudan erişmediği için server/client ownership sınırı korunur.

Singleton Store Problemi

Module-level singleton Redux store klasik SPA'de yaygın pattern olabilir. Next.js server rendering ortamında aynı store farklı request'ler tarafından paylaşılabilir. User veya tenant verisi store'a yazıldığında data leakage riski oluşur. Development server düşük concurrency nedeniyle problemi görünmez bırakabilir. App Router için request-safe store factory kullanmak bu nedenle temel gereksinimdir.

Request Başına Store Factory

Factory function her server render için yeni Redux store oluşturur. Reducer ve middleware configuration tek yerde kalır. Initial preloaded state factory'ye parametre olarak verilebilir veya provider initialization action gönderebilir. Testler de aynı factory ile bağımsız store instance'ları üretir. Request isolation automatic assumption değil explicit architecture pattern hâline gelir.

Client Provider Pattern

React Redux Provider context kullandığı için Client Component içinde yer alır. Provider store'u ilk render'da oluşturur ve re-render sırasında aynı instance'ı korur. Provider yalnız Redux gereken subtree'yi sarmalıdır. Root'a otomatik koymak gereksiz client boundary genişletebilir. Feature veya route-specific store ilgili layout altında konumlandırılabilir.

Initial State Hydration

Server'ın bildiği initial client state serializable prop ile Provider'a aktarılabilir. Store ilk oluşturulurken bu state ile initialize edilir. Client ilk render server output ile aynı değeri görür ve hydration uyumu korunur. `useEffect` ile sonradan initialize etmek flicker veya mismatch üretebilir. Initial state yalnız client store'un gerçekten sahip olacağı mutable data için taşınmalıdır.

Route-Specific State

Product edit route'a ait draft state tüm application yaşamı boyunca saklanmak zorunda değildir. Store Provider route boundary içinde oluşturulursa navigation sonrası state doğal olarak temizlenebilir. Root store kullanılıyorsa route değişiminde explicit reset action gerekebilir. Route state'in global state ile aynı slice içinde karışması stale data hatalarını artırır. Scope seçimi reset logic'inden daha basit çözüm olabilir.

Route Değişiminde State Reset

Client-side navigation layout'u koruduğunda root provider içindeki store yaşamaya devam edebilir. Route-specific slice eski entity state'ini yeni route'a taşıyabilir. Route id değişikliğinde initialization ve reset strategy uygulanmalıdır. Provider'ı daha aşağı taşımak bu ihtiyacı azaltabilir. Navigation testleri route A'dan route B'ye geçişte eski state kalmadığını doğrulamalıdır.

RSC ve Redux Sınırı

RSC Redux hook veya context kullanmamalıdır. Server veriyi kendi data access layer'ından alır. Gerekiyorsa Client Component'a initial prop gönderir ve Redux provider client tarafında state'i initialize eder. Bu separation Redux store'u server cache veya request context yerine koyma eğilimini engeller. RSC ile Redux arasındaki boundary architecture document içinde açık biçimde tanımlanmalıdır.

Redux Store'u Business Domain'lere Bölmek

Büyük Redux store'u dosya türlerine göre değil business domain'lere göre organize etmek ownership'i daha anlaşılır hâle getirir. Identity, cart, checkout, billing ve notification state'leri ayrı feature boundary oluşturabilir. UI-only state business domain'lerden ayrılabilir. Cross-domain action gerektiğinde doğrudan slice içi veri erişimi yerine açık event veya coordination pattern kullanılabilir. Domain-oriented yaklaşım takım sorumluluğu ve test scope'unu daha net hâle getirir.

Domain-Driven State Management

Domain-driven state management store shape'i business capability'lere göre böler. `cart.items`, `checkout.step` veya `billing.invoiceDraft` gibi alanlar teknik component adına göre daha anlamlıdır. Feature ekipleri kendi selector ve action API'sinin sahibi olur. Internal state shape dış component'lara doğrudan expose edilmez. Domain sınırı refactoring sırasında değişiklik alanını küçültür.

Identity Domain

Identity domain client'ın server session snapshot'ından türetilen UI bilgisini taşıyabilir. Gerçek authentication ve permission source of truth server'da kalmalıdır. Client store yalnız avatar display, optimistic profile edit veya session-related UI state için kullanılabilir. Logout action diğer sensitive domain state'lerini resetlemek için koordinasyon başlatabilir. Identity slice'ın access token vault'a dönüşmesine izin verilmemelidir.

Cart Domain

Cart domain ürün seçimi, quantity ve local interaction state'ini yönetebilir. Server-side cart varsa client state authoritative değil local representation olur. Mutation conflict ve price change senaryoları reconciliation gerektirir. Guest cart persistence kullanılacaksa schema versioning düşünülmelidir. Cart total gibi derived değer selector üzerinden hesaplanabilir.

Checkout Domain

Checkout domain çok adımlı workflow ve validation state'i taşıyabilir. Shipping, payment ve confirmation adımları explicit transition ile yönetilmelidir. Sensitive payment data store içinde gereksiz tutulmamalıdır. Server validation her kritik geçişte authoritative olmalıdır. Karmaşık checkout state machine yaklaşımına da güçlü adaydır.

Billing Domain

Billing domain client-side invoice selection veya form draft gibi mutable state içerebilir. Gerçek invoice ve subscription data server-owned olmalıdır. Browser store'a bütün billing response'unu kopyalamak yerine query cache kullanılabilir. Payment status stale kalmamalı ve server'da yeniden doğrulanmalıdır. Domain store yalnız business interaction'a gerçekten gerekli state'i taşımalıdır.

Notifications Domain

Notification state unread indicator, local dismissal veya toast queue gibi browser-owned alanları içerebilir. Server notification listesi query cache veya server render üzerinden gelebilir. Read mutation sonrası server ve client cache invalidation yapılmalıdır. UI toast ile persistent notification birbirinden ayrılmalıdır. Aynı domain adı altında farklı ownership türlerini karıştırmamak gerekir.

UI Domain

Sidebar, theme toggle veya global modal host gibi application-level UI state ayrı domain içinde tutulabilir. Business data bu slice'a taşınmamalıdır. UI state'in çoğu persistence gerektirmeyebilir. Theme gibi preference localStorage veya cookie ile saklanabilir. UI domain'in sınırsız “misc” store'a dönüşmemesi için scope açık tutulmalıdır.

Cross-Domain Action Tasarımı

Checkout tamamlandığında cart reset ve notification update gibi birden fazla domain etkilenebilir. Bir slice'ın diğer slice internal state'ine doğrudan erişmesi coupling oluşturur. Ortak business event veya listener middleware coordination sağlayabilir. Transaction server'da authoritative olarak tamamlanmalıdır. Client cross-domain action yalnız UI state'in tutarlı transition'ını yönetmelidir.

Redux Toolkit Selector Stratejisi

Selector stratejisi component'ların store internal shape'ine ne kadar bağlandığını ve hangi state değişikliğinde render olduğunu belirler. Büyük projede selector yalnız performance aracı değil public domain API'dir. Derived state selector içinde hesaplanabilir. Memoized selector pahalı hesapların gereksiz tekrarını azaltır. Component'ın `state.checkout.internal.deep.field` gibi path'leri bilmemesi refactoring güvenliğini artırır.

Selector Neden Önemlidir?

Selector component ile store arasında abstraction katmanı oluşturur. Store shape değişse bile selector contract aynı kalabilir. Component yalnız ihtiyaç duyduğu data'ya subscribe olur. Derived business logic farklı component'larda tekrar edilmez. Büyük ekipte selector convention store erişimini standardize eder.

createSelector ile Memoization

`createSelector` input değerleri değişmediğinde pahalı derived hesaplamayı tekrar yapmamayı sağlar. Büyük collection filtreleme veya permission mapping için faydalıdır. Her küçük scalar selector için memoization gerekmeyebilir. Selector output referential stability component render davranışını etkileyebilir. Performance optimizasyonu gerçek profiler verisine göre uygulanmalıdır.

Derived State

Cart subtotal, selected item count veya `canProceed` gibi değerler store'a ayrıca yazılmak yerine selector ile hesaplanabilir. Böylece base state değiştiğinde derived değer otomatik güncel olur. Duplicate field senkronizasyonu ortadan kalkar. Hesaplama pahalıysa memoized selector kullanılabilir. Derived state prensibi store'u daha küçük ve daha güvenilir tutar.

Selector'ları Domain Katmanında Tutmak

Selector'lar component klasörlerine dağılırsa aynı business logic farklı yerlerde tekrar yazılabilir. Domain package kendi selector API'sini export edebilir. Bu yapı business state modelinin tek sahibi olmasını sağlar. Testler selector'ları bağımsız doğrulayabilir. Public selector'lar internal store shape için stabil facade görevi görür.

Component'ların Store Shape'e Bağımlılığını Azaltmak

Component store'un internal nested yapısını biliyorsa her refactoring geniş UI değişikliği gerektirir. `selectCheckoutCanContinue` gibi semantic selector bu bağımlılığı azaltır. Store normalization veya slice merge işlemi component'tan gizlenebilir. Mock testlerde selector contract üzerinden daha sade setup yapılabilir. Kurumsal codebase'de store encapsulation long-term bakım maliyetini ciddi biçimde düşürür.

TanStack Query ile Server State Yönetimi

TanStack Query browser tarafında asynchronous server state cache, refetch, stale policy ve mutation yönetimini standartlaştırır. Global client state manager değildir ve modal veya sidebar state'inin yerini almak için tasarlanmamıştır. Live dashboard, background refetch, pagination veya optimistic mutation gibi senaryolarda güçlü değer üretir. Query key, staleTime ve invalidation policy domain gereksinimine göre açıkça tasarlanmalıdır. App Router ile birlikte kullanıldığında Server Component prefetch ve HydrationBoundary sayesinde server-rendered initial data ile browser cache aynı akışta birleştirilebilir.

TanStack Query Hangi Problemi Çözer?

Server response'un loading, error, retry, stale, refetch ve cache lifecycle problemlerini çözer. Aynı data'ya birden fazla component eriştiğinde request deduplication ve shared cache sağlar. Mutation sonrası ilgili query'leri invalidatedebilir. Offline veya background refetch davranışları eklenebilir. Bu özellikler server state'i Redux veya Zustand içine manuel kopyalama ihtiyacını azaltır.

Query Key Tasarımı

Query key cache kimliğidir ve domain data'nın hangi parametrelere göre farklılaştığını ifade etmelidir. Tenant, user scope, filter ve pagination gibi değerler gerektiğinde key içine dahil edilmelidir. Çok generic key yanlış cache paylaşımına yol açabilir. Key factory domain package içinde standardize edilebilir. Invalidation policy de aynı key taxonomy üzerinden çalıştığı için tasarım baştan dikkatle yapılmalıdır.

staleTime

`staleTime` query data'nın ne kadar süre fresh kabul edileceğini belirler. Default davranış her query için uygun olmayabilir. Reference data dakikalarca fresh kalabilirken live operational data saniyeler içinde refetch gerekebilir. Çok düşük staleTime gereksiz network çağrısı, çok yüksek değer stale UI yaratabilir. Business freshness gereksinimi teknik süreye çevrilmelidir.

gcTime

`gcTime` inactive query cache'inin memory'de ne kadar süre tutulacağını belirler. Bu değer freshness ile aynı kavram değildir. Kullanıcı route'tan ayrıldıktan sonra kısa süre geri dönecekse cache retention deneyimi hızlandırabilir. Çok geniş cache yüksek memory kullanımına yol açabilir. SSR ve server rendering davranışında QueryClient lifecycle ile birlikte değerlendirilmelidir.

Query Invalidation

Mutation sonrası hangi query'nin stale hâle geleceği açıkça tanımlanmalıdır. `invalidateQueries` matching key'leri stale işaretleyip active query'leri background refetch edebilir. Her mutation sonrası bütün cache'i temizlemek gereksiz network maliyeti üretir. Domain-specific key prefix kullanmak hedefli invalidation sağlar. Invalidation unutulması stale UI'nın en yaygın nedenlerinden biridir.

Background Refetch

Cached data kullanıcıya hemen gösterilirken query arka planda yenilenebilir. Bu model dashboard veya collaborative uygulamada iyi kullanıcı deneyimi sağlar. Refetch sırasında mevcut data ekranda kalabilir. User-facing loading state ile background fetching indicator ayrılabilir. Freshness ihtiyacı düşük sayfalarda background refetch gereksiz olabilir.

Retry Politikaları

Geçici network hatası retry ile çözülebilir, validation veya 401 gibi hatalar tekrar denemeyle düzelmez. Query ve mutation için retry policy response türüne göre ayarlanmalıdır. Exponential backoff downstream service'i korur. Critical action duplicate side effect üretmemelidir. Retry behavior observability dashboard'unda görünür olmalıdır.

Pagination ve Infinite Query

Pagination query key içinde page veya cursor bilgisini taşıyabilir. Infinite Query feed ve endless list senaryolarında page data'yı yönetir. UI state ile server cache birbirinden ayrılır. URL pagination state'i shareable olduğu için global store yerine URL'de tutulabilir. Query cache URL'deki page'e karşılık gelen server data'yı yönetir.

TanStack Query + Next.js App Router

App Router ile TanStack Query kullanırken server prefetch ve client cache arasında açık hydration contract kurulmalıdır. Server Component request-scoped QueryClient ile query prefetch edebilir. `dehydrate()` sonucu HydrationBoundary üzerinden Client Component tarafına aktarılır. Browser QueryClient daha sonra aynı query key ile data'yı kullanabilir ve gerektiğinde refetch yapabilir. Bu yaklaşım initial server render ile client-side canlı cache ihtiyacını birlikte karşılar.

Server Component'ta Prefetch

Server Component query data'yı browser'a gelmeden önce prefetch edebilir. Critical query await edilerek initial HTML içinde hazır bulunabilir. Daha düşük öncelikli query streaming yaklaşımıyla pending olarak taşınabilir. Query function server ve client'ta kullanılacaksa authentication ve environment farkları düşünülmelidir. Prefetch request waterfall'larını azaltmak için mümkün olduğunca paralel başlatılmalıdır.

QueryClient Request Scope

Server tarafında aynı QueryClient'ı bütün request'ler arasında paylaşmak cache isolation problemi yaratabilir. Request başına yeni QueryClient oluşturmak user ve tenant data'nın karışmasını önler. Browser tarafında ise session boyunca aynı client instance'ı korunabilir. Bu iki lifecycle birbirinden farklıdır. QueryClient factory server ve browser davranışını açıkça ayırmalıdır.

dehydrate()

`dehydrate()` QueryClient cache state'ini transport edilebilir forma dönüştürür. Server'da prefetched query'ler bu state üzerinden client cache'e aktarılır. Sensitive server-only data hydrate edilmemelidir. Serialization policy non-standard data type'lar için ayrıca düşünülmelidir. Dehydrated payload client'a gönderildiği için yalnız gerçekten client'ta kullanılacak query'leri taşımak page payload'ını kontrol altında tutar.

HydrationBoundary

`HydrationBoundary` server'da dehydrated edilen query cache'i ilgili client subtree'ye yükler. Boundary route veya feature bazında yerleştirilebilir. Bütün application cache'ini root'ta tek büyük payload olarak taşımak zorunlu değildir. Nested boundaries feature isolation sağlayabilir. Client `useQuery` aynı key üzerinden hazır data'yı kullanabilir.

Streaming ve Suspense

App Router Suspense boundary'leri üzerinden hazır content'i streaming ile gönderebilir. TanStack Query prefetch bu modele uyumlu çalışabilir. Critical data await edilirken daha düşük öncelikli query pending olarak hydrate edilebilir. Kullanıcı tüm page data'sını beklemek zorunda kalmaz. Streaming stratejisi loading UX ve error boundary tasarımıyla birlikte düşünülmelidir.

Request Waterfall'larını Önleme

Bir Client Component mount olduktan sonra query başlatır, onun sonucuyla ikinci query'yi açarsa initial render'da waterfall oluşabilir. Server prefetch ihtiyaçları önceden bildiği için query'leri paralel başlatabilir. Nested Server Component'lar da kendi data'sını erken fetch edebilir. Network trace kritik waterfall'ları görünür kılmalıdır. Prefetch her data için yapılmamalı, kullanıcı ilk deneyiminde gerekli olan query'lere öncelik verilmelidir.

Client Refetch Ne Zaman Gerekli?

Server-rendered data uzun süre aynı kalıyorsa browser refetch gerekmeyebilir. Live dashboard, focus sonrası güncelleme veya mutation sonrası fresh data gerekiyorsa client refetch değerlidir. staleTime business ihtiyacına göre ayarlanmalıdır. Client cache sırf library standart olduğu için bütün server-rendered sayfalara eklenmemelidir. Server ve client fetching sorumluluğu ekranın interaction modeline göre belirlenmelidir.

Optimistic Updates Kurumsal Ölçekte Nasıl Yönetilir?

Optimistic update kullanıcı aksiyonunu server cevabı gelmeden UI'da başarılıymış gibi gösterir. Bu teknik doğru use case'te akıcı deneyim sağlar, ancak rollback ve concurrency doğru tasarlanmazsa kullanıcıya yanlış state gösterebilir. TanStack Query cache snapshot ve mutation lifecycle bu pattern'i destekler. Kritik finansal veya geri alınması zor işlemlerde optimistic davranış daha dikkatli değerlendirilmelidir. Kurumsal projede optimistic update yalnız hızlı hissettirmek değil tutarlı reconciliation sağlamak anlamına gelir.

Optimistic UI Ne Zaman Kullanılmalı?

Like, item reorder veya düşük riskli preference update optimistic UI için iyi adaydır. Server rejection ihtimali düşük ve rollback kolay olmalıdır. Payment confirmation gibi irreversible işlemde kullanıcıya erken başarı göstermek yanlış güven oluşturabilir. Business risk UI hızından daha önemlidir. Her mutation için optimistic olup olmayacağı domain policy içinde ayrı kararlaştırılmalıdır.

Cache Snapshot

Cache üzerinde optimistic değişiklik yapmadan önce önceki değer saklanabilir. Mutation başarısız olursa snapshot rollback için kullanılır. Snapshot yalnız etkilenen query data'yı kapsamalıdır. Büyük cache kopyalamak gereksiz memory maliyeti oluşturabilir. Concurrent mutation varsa tek snapshot modelinin yeterli olup olmadığı ayrıca test edilmelidir.

Optimistic Mutation

Mutation başlamadan UI beklenen yeni state'e geçirilir. Pending item geçici id veya visual marker taşıyabilir. Server sonucu geldiğinde gerçek id ve canonical data ile reconcile edilir. Mutation aynı data'yı kullanan birden fazla query'yi etkiliyorsa cache update dikkatle yapılmalıdır. Basit senaryoda UI-level optimistic rendering cache manipulation'dan daha kolay olabilir.

Error Durumunda Rollback

Mutation başarısız olduğunda optimistic değişiklik geri alınmalıdır. Kullanıcıya error mesajı ve retry seçeneği sunulabilir. Rollback eski snapshot'ı körü körüne uyguladığında daha yeni concurrent mutation'ı ezmemelidir. Query refetch bazı durumlarda canonical server state'i geri getirmek için daha güvenlidir. Error recovery unit ve integration testte açıkça doğrulanmalıdır.

Server Response ile Reconciliation

Server response optimistic tahminden farklı olabilir. Price, permission veya normalized entity server tarafından değiştirilebilir. Client cache server cevabıyla reconcile edilmelidir. Mutation success'i yalnız local optimistic state'e güvenmemelidir. Canonical server payload veya invalidation sonucunda UI gerçek data'ya dönmelidir.

Concurrent Mutation Problemleri

Kullanıcı aynı item üzerinde arka arkaya değişiklik yapabilir. İlk mutation'ın geç gelen response'u ikinci optimistic state'i ezebilir. Mutation ordering, request id veya server version kullanımı gerekebilir. TanStack Query concurrent optimistic pattern'leri desteklese de business conflict logic uygulamaya aittir. Collaboration yoğun ekranlarda server-side concurrency kontrolü şarttır.

Optimistic Update Testleri

Success path kadar failure ve out-of-order response test edilmelidir. Snapshot rollback doğru state'e dönüyor mu kontrol edilir. Aynı entity üzerinde iki mutation yarıştığında sonuç doğrulanır. Network timeout ve retry senaryosu eklenir. Testler optimistic UX'in data consistency pahasına çalışmadığını göstermelidir.

RTK Query mi TanStack Query mi?

RTK Query ve TanStack Query server state problemini çözmek için güçlü araçlardır, ancak ekosistem entegrasyonu farklıdır. Redux zaten merkezi client architecture'ın temel parçasıysa RTK Query convention ve DevTools bütünlüğü sağlayabilir. TanStack Query Redux'tan bağımsız server-cache katmanı olarak kullanılabilir. App Router'ın server-first yaklaşımında current Redux guidance server fetching için RSC fetch kullanımını, RTK Query'yi ise client tarafındaki fetching için konumlandırır. Seçim yalnız feature listesine değil ekip standardı, SSR pattern'i ve client interaction ihtiyacına göre verilmelidir.

Redux Zaten Kullanılıyorsa RTK Query

Redux Toolkit bütün client state mimarisinde zaten standartsa RTK Query aynı package ecosystem içinde server cache sunar. Query endpoint'leri Redux DevTools ve middleware akışıyla entegre olur. Ekip yeni bir cache library öğrenmez. Bununla birlikte App Router server fetching pattern'i ayrıca değerlendirilmelidir. RTK Query kullanım alanı client tarafında canlı server state ihtiyacıyla sınırlı tutulabilir.

Server-State Odaklı Bağımsız Katman Olarak TanStack Query

Redux kullanmayan projede yalnız server cache ihtiyacı için Redux eklemek gereksiz olabilir. TanStack Query bağımsız QueryClient üzerinden query ve mutation yönetir. Zustand ile browser-owned state, TanStack Query ile server state birlikte rahatça kullanılabilir. Bu separation ownership modelini net tutar. Client cache yalnız canlı interaction gereken route'larda provider altında kullanılabilir.

Cache Invalidation Karşılaştırması

Her iki araç query key veya tag benzeri identity üzerinden invalidation sağlar. Tasarım kalitesi library isminden çok cache taxonomy'ye bağlıdır. Domain mutation hangi cache entry'lerini etkilediğini bilmelidir. Çok geniş invalidation gereksiz refetch üretir, dar invalidation stale data bırakabilir. Cache policy architecture guideline içinde standartlaştırılmalıdır.

Developer Experience

RTK Query Redux Toolkit bilen ekip için doğal extension hissi verir. TanStack Query daha bağımsız ve server-state odaklı zihinsel model sunar. Devtools ve TypeScript desteği iki tarafta da güçlüdür. Developer experience yalnız ilk hook syntax'ı değil debugging, SSR ve migration süreçleriyle ölçülmelidir. Organization mevcut standardı değiştirmeden önce gerçek pain point'i ortaya koymalıdır.

App Router Uyumu

TanStack Query resmi advanced SSR rehberi Server Components, prefetch, `dehydrate` ve HydrationBoundary pattern'lerini ayrıntılı biçimde ele alır. Redux'ın Next.js rehberi ise server fetch için RSC kullanımını ve RTK Query'yi client fetching için önerir. Bu fark App Router architecture seçiminde dikkate alınmalıdır. Her iki araç Client Components içinde rahat çalışır. Initial server data ve request isolation için framework-specific pattern doğru kurulmalıdır.

Kurumsal Ekip Standardizasyonu

Bir kurum aynı probleme üç farklı query library kullandığında onboarding ve debugging maliyeti büyür. Approved default belirlemek faydalıdır. İstisna gerektiğinde gerekçe ADR ile kayıt altına alınabilir. Shared query key veya endpoint convention geliştirilebilir. Standardizasyon yeniliği engellemek değil ortak operasyon modelini korumak için kullanılmalıdır.

Zustand mı Redux Toolkit mi?

Zustand ve Redux Toolkit karşılaştırması “hangisi daha modern?” sorusuyla değil organizasyon ve state modeliyle yapılmalıdır. Zustand daha küçük API ve düşük ceremony ile shared browser state için hızlıdır. Redux Toolkit büyük ekipte explicit convention, middleware ve action trace avantajı sağlar. Complex business workflow ve audit gereksinimi Redux lehine sinyal verebilir. Küçük veya orta ölçekli browser-owned state için Zustand daha düşük geliştirme yükü sağlayabilir.

Mimari Convention

Redux Toolkit slice, action ve selector gibi güçlü ortak convention getirir. Zustand daha serbesttir ve ekip kendi store layout standardını belirler. Küçük ekip bu esneklikten faydalanabilir. Büyük ekipte store'ların birbirinden çok farklı yazılması bakım maliyeti yaratabilir. Library seçimi ekip governance kapasitesiyle birlikte değerlendirilmelidir.

Boilerplate

Zustand birkaç satırda store oluşturmayı sağlar. Redux Toolkit klasik Redux'a göre boilerplate'i ciddi biçimde azaltmış olsa da daha fazla yapı sunar. Bu yapı complex workflow'da faydalı, basit UI state'inde gereksiz olabilir. Kod satırı sayısı tek karar metriği değildir. Okunabilirlik ve transition güvenliği uzun vadede daha değerlidir.

Büyük Ekiplerde Öğrenilebilirlik

Redux geniş dokümantasyon ve yaygın convention sayesinde farklı ekiplerde benzer code structure üretir. Zustand syntax olarak daha hızlı öğrenilebilir. Ancak architecture convention standardize edilmezse aynı library ile farklı mental model'ler oluşabilir. Onboarding yalnız API öğrenmek değil repository'deki state kurallarını anlamaktır. Organization kendi örnek reference implementation'ını sağlamalıdır.

Middleware

Redux middleware merkezi action pipeline üzerinde güçlü kontrol sunar. Logging, listener ve policy pattern'leri kolay standardize edilir. Zustand middleware daha hafif capability'ler sağlar. Business side effect sayısı büyüdükçe explicit pipeline avantajı artabilir. Middleware kullanımı library seçiminin tek kriteri olmamalıdır.

Debugging ve DevTools

Redux DevTools action history ve state diff açısından çok güçlüdür. Zustand da devtools middleware ile debugging sağlayabilir. Kurumsal incident sırasında action taxonomy Redux modelinde daha doğal biçimde görünür olabilir. Zustand action API iyi isimlendirilirse benzer operasyon avantajı elde edilebilir. Debugging standardı development tool yanında production telemetry'yi de kapsamalıdır.

Test Edilebilirlik

Her iki library store logic'ini component'tan bağımsız test etmeye izin verir. Redux reducer pure function olarak son derece doğrudan test edilir. Zustand factory yeni store instance oluşturduğu için isolation testleri kolaylaşır. Selector ve action contract'ları ayrı test edilmelidir. Test edilebilirlik doğru architecture ile iki tarafta da güçlüdür.

Complex Business Workflows

Çok adımlı ve cross-domain transition yoğun state Redux Toolkit'in explicit action modelinden faydalanabilir. Zustand da teknik olarak aynı state'i yönetebilir, ancak convention tamamen ekip sorumluluğundadır. Workflow kritikse state machine daha da iyi model olabilir. Library capability'den önce business transition'ların açık ifade edilip edilmediğine bakılmalıdır. “Yapabiliyor” ile “en iyi model” aynı şey değildir.

Refactoring Güvenliği

Redux selector ve action facade internal store shape'i component'lardan gizlerse güçlü refactoring alanı sağlar. Zustand da aynı pattern ile kullanılabilir. Component store object'in tamamını doğrudan okursa coupling artar. TypeScript compile-time güvenliği refactoring sırasında yardımcı olur. Store public API tasarımı library isminden daha belirleyici faktördür.

React Context Ne Zaman Yeterlidir?

React Context küçük ve nispeten stabil shared value'lar için çoğu zaman yeterlidir. Theme, locale veya environment configuration bu profile uyar. Context provider scope dar tutulduğunda gereksiz render ve client boundary etkisi azalır. Context içine her API response ve action'ı doldurmak onu manuel global store'a dönüştürebilir. State sık değişiyor veya selective subscription ihtiyacı büyüyorsa Zustand ya da Redux gibi store çözümü daha uygun olabilir.

Theme

Theme value geniş subtree tarafından okunur fakat çok sık değişmez. Context bu kullanım için doğal araçtır. Theme cookie üzerinden server'da belirlenip Client Provider'a başlangıç değeri verilebilir. Browser persistence gerektiğinde güvenli storage stratejisi eklenir. Yalnız renk theme'i için global Redux slice açmak çoğu projede gereksizdir.

Locale

Locale route veya request bilgisine bağlı olabilir. Client component'ların translation context'e ihtiyacı varsa Context kullanılabilir. Source of truth URL veya server route olabilir. Context yalnız resolved locale değerini subtree'ye aktarır. Dil seçim state'ini server ve client'ta iki ayrı gerçek hâline getirmemek gerekir.

Stable Configuration

Feature configuration veya static environment setting sık değişmiyorsa Context ile taşınabilir. Value her render'da yeni object oluşturulmamalıdır. Server-secret configuration client Context içine konmamalıdır. Public configuration build veya server props üzerinden aktarılabilir. Stable value Context'ın güçlü kullanım alanlarından biridir.

Context Provider'ın Dar Bir Subtree'de Tutulması

Provider yalnız value'ya ihtiyaç duyan component ağacını sarmalıdır. Root layout'u gereksiz Client Component ağına çevirmemek gerekir. Feature-specific Context ilgili feature boundary içinde konumlandırılabilir. Böylece başka route'lar provider dependency'si taşımaz. Scoped provider architecture bundle ve ownership açısından daha temizdir.

Context'ın Global Store'a Dönüşmeye Başladığını Gösteren İşaretler

Context value onlarca mutable field ve action taşımaya başladığında dikkat gerekir. Her küçük değişiklik çok sayıda consumer'ı render ediyorsa subscription granularity eksikliği ortaya çıkar. Domain logic provider içine yığılıyorsa test ve debugging zorlaşır. Birden fazla Context yalnız re-render çözmek için açılıyorsa daha uygun store değerlendirilebilir. Context basit dependency sharing aracıyken görünmez state framework'üne dönüşmemelidir.

Jotai Ne Zaman Tercih Edilebilir?

Jotai atomic state modeliyle küçük ve bağımsız client state parçalarını ayrı atom'lar olarak tanımlamayı sağlar. Fine-grained subscription component'ın yalnız kullandığı atom değiştiğinde etkilenmesine yardımcı olabilir. Çok sayıda bağımsız client island'ın bulunduğu uygulamalarda doğal model sunabilir. Bununla birlikte yüzlerce atom organization standardı olmadan dağıldığında ownership görünürlüğü azalabilir. Kurumsal ekipte atom naming, placement ve domain boundary kuralları açık olmalıdır.

Atomic State Modeli

Her atom küçük bir state veya derived value temsil eder. Component'lar ihtiyaç duyduğu atom kombinasyonunu kullanır. Büyük merkezi store shape'i yerine composition yaklaşımı oluşur. Bu model bağımsız feature'larda esneklik sağlar. Cross-domain workflow büyüdükçe atom dependency graph'ını yönetmek önem kazanır.

Fine-Grained Subscription

Component yalnız tükettiği atom'a subscribe olduğu için unrelated state değişiklikleri daha az render etkisi yaratır. Performance avantajı özellikle sık güncellenen küçük state parçalarında değerli olabilir. Derived atom başka atomlardan hesaplanan state'i saklamadan üretir. Profiling yine gereklidir. Fine-grained subscription architecture hatalarını otomatik gizlememelidir.

Bağımsız Client Island'lar

Sayfada birbirinden bağımsız widget'lar varsa atomic state her widget'ın küçük state graph'ını kurabilir. Server Component etrafında client island'lar kendi atom scope'una sahip olabilir. Global coordination gerekmeyen state doğal biçimde lokal kalır. Provider ihtiyacı kullanılan setup'a göre sınırlı olabilir. Bu yapı client-heavy editor veya dashboard bölümlerinde değerlendirilebilir.

Büyük Ekiplerde Atom Dağınıklığı Riski

Atom'lar herhangi bir klasörde rastgele oluşturulursa state ownership zamanla belirsizleşir. Aynı business kavramı için farklı atom'lar ortaya çıkabilir. Domain package ve export policy oluşturmak gerekir. Public atom yerine domain hook veya facade sunmak coupling'i azaltabilir. Atomic modelin esnekliği governance eksikliğinde dağınıklığa dönüşmemelidir.

State Machine Gerektiren Kurumsal Workflow'lar

Her workflow birkaç boolean ve step number ile güvenli biçimde modellenemez. Checkout, onboarding ve approval gibi süreçlerde izin verilen geçişlerin açıkça tanımlanması gerekir. State machine mevcut state, event ve next state ilişkisini explicit hâle getirir. Impossible state'leri azaltır ve test case'lerini business transition üzerinden yazmayı kolaylaştırır. Kritik workflow için state machine, generic Redux veya Zustand store'dan daha doğru abstraction olabilir.

Normal State Store ile Workflow State Arasındaki Fark

Normal store value'ların nerede tutulduğunu çözer. State machine ise hangi state'ten hangi event ile hangi state'e geçilebileceğini tanımlar. `isLoading`, `isSuccess`, `hasError`, `step` gibi bağımsız flag'ler impossible combination üretebilir. Machine `idle`, `submitting`, `success`, `failure` gibi mutually exclusive durumları açık tutar. Workflow complexity arttıkça transition modelinin değeri artar.

Checkout Süreçleri

Checkout shipping, payment authorization ve confirmation gibi sıralı adımlara sahiptir. Bazı adımlara geri dönülebilir, bazıları server confirmation bekler. Payment success olmadan completed state'e geçilmemelidir. State machine bu guard ve transition'ları explicit tutar. Server yine transaction source of truth olarak kalmalıdır.

Onboarding

Onboarding adımları kullanıcı role veya önceki seçimlere göre dallanabilir. Basit `currentStep + 1` modeli bu branching büyüdüğünde yetersiz kalabilir. Machine guard hangi adımın atlanacağını belirler. Resume veya persisted progress ayrı state olarak yönetilebilir. Analytics transition event'leri onboarding drop-off analizini kolaylaştırır.

Approval Workflow

Approval süreçleri draft, submitted, approved, rejected ve cancelled gibi açık state'lere sahiptir. Her role her transition'ı yapamaz. Client state machine UI akışını modelleyebilir, ancak gerçek authorization server tarafından doğrulanmalıdır. Rejection sonrası düzeltme ve yeniden gönderim açık transition'dır. Bu model audit ihtiyacı olan sistemlerde özellikle değerlidir.

Payment State

Payment işleminde initiated, pending, authorized, captured, failed veya refunded gibi durumlar bulunabilir. Client yalnız server payment status'unun snapshot'ını gösterir. Optimistic success uygun değildir. State machine UI'nın hangi transition'ı göstereceğini düzenler. Server payment provider callback ve database state gerçek kaynaktır.

Explicit State Transition'ların Avantajı

Transition'lar event isimleriyle açık olduğunda code review business flow üzerinden yapılabilir. Her transition ayrı test edilir. Impossible state kombinasyonları azalır. Analytics ve logging event taxonomy ile uyumlu hâle gelir. Yeni workflow adımı eklemek mevcut transition graph üzerindeki etkisini görünür yapar.

State Machine Ne Zaman Redux/Zustand'dan Daha İyi Bir Modeldir?

State'in değeri kadar state geçiş kuralları önemliyse machine güçlü adaydır. Çok sayıda boolean guard, branching ve retry flow varsa generic store logic hızla zorlaşır. Redux veya Zustand machine state'ini barındırabilir, ancak transition modelinin kendisi state machine olarak kalabilir. Library'ler rakip olmak zorunda değildir. Doğru abstraction business davranışını en açık ifade eden modeldir.

Authentication State Nasıl Yönetilmelidir?

Authentication state'in gerçek source of truth'ı server olmalıdır. Browser'daki user object veya `isAuthenticated` değeri yalnız mevcut session'ın UI snapshot'ıdır. Authorization kararı hiçbir zaman yalnız client store'a dayanmaz. Session expiration, logout ve permission değişikliği server tarafından doğrulanmalıdır. Client cache ve store logout sonrası temizlenerek başka kullanıcıya ait verinin aynı browser session'ında kalması engellenmelidir.

Authentication Source of Truth Server Olmalıdır

Session database, secure cookie veya identity provider server tarafında doğrulanır. Client store kullanıcı giriş yapmış görünüyor diye backend yetki vermemelidir. Server Component session'ı request sırasında okuyabilir. Client'a yalnız ihtiyaç duyulan public user bilgisi gönderilir. Bu model UI convenience ile security boundary'yi birbirinden ayırır.

Client'taki User State Bir Snapshot'tır

Client user object server session'ın belirli andaki görünümüdür. Role veya profile başka yerde değişebilir. Background refetch veya route refresh yeni snapshot getirebilir. Store içinde yıllarca yaşayan immutable “gerçek user” varsayımı stale permission sorunları oluşturur. UI data'nın snapshot olduğunu kabul ederek freshness politikasını tanımlamalıdır.

Session Expiration

Session süresi dolduğunda client request 401 veya auth redirect ile karşılaşabilir. Global error handling ilgili client cache'i temizleyebilir. Kullanıcı pending form state'i varsa güvenli şekilde koruma veya uyarı stratejisi düşünülebilir. Refresh token mekanizması kullanılıyorsa server güvenlik modeliyle yönetilmelidir. Session expiration farklı library'lerin kendi `isLoggedIn` flag'ine bırakılmamalıdır.

Logout Sonrası Cache Temizliği

Logout yalnız auth cookie silmek değildir. TanStack Query cache, Redux domain state, Zustand persisted state ve browser storage içinde user-specific data temizlenmelidir. Aynı cihazda başka user login olduğunda eski data görünmemelidir. Public preference state korunabilir. Central logout orchestration hangi store ve cache'in resetleneceğini açıkça tanımlamalıdır.

Role ve Permission State

Permission source of truth server'da tutulmalıdır. Client permission listesi yalnız UI'da button veya route görünürlüğünü ayarlamak için kullanılabilir. Backend her kritik operation'da authorization yapmaya devam eder. Permission query key user veya tenant kimliğini içermelidir. Role değişikliği olduğunda ilgili client cache invalidatedilmelidir.

Multi-Tab Authentication Senaryoları

Kullanıcı bir tab'da logout olduğunda diğer tab'ın session state'i stale kalabilir. Storage event, BroadcastChannel veya server response üzerinden multi-tab sync sağlanabilir. Client store yalnız local tab state'i olduğu için otomatik güncellenmeyebilir. Sensitive ekranlar server session'ı periyodik veya navigation sırasında yeniden doğrulayabilir. Multi-tab test kurumsal auth flow checklist'ine eklenmelidir.

Global Auth Store Kullanmanın Riskleri

Global auth store UI convenience sağlar ancak security source of truth gibi kullanılmaya başlanırsa problem oluşur. Token localStorage ve store içinde tutulduğunda XSS riskinin etkisi artar. Server session ile client flag senkron olmayabilir. Auth store logout orchestration ve UI snapshot ile sınırlı tutulabilir. Gerçek permission ve identity doğrulaması server sınırında kalmalıdır.

Multi-Tenant Next.js Uygulamalarında State Management

Multi-tenant sistemde state management'ın en önemli hedefi tenant verisinin bütün katmanlarda izole kalmasıdır. Request context, server cache, QueryClient key'leri ve client store reset davranışı tenant bilgisini dikkate almalıdır. Tenant A'dan Tenant B'ye geçişte eski cache'in görünmesi ciddi veri güvenliği problemidir. Singleton server store bu riskin en tehlikeli örneklerinden biridir. Tenant identity cache ve store key tasarımının birinci sınıf parçası olmalıdır.

Tenant Context

Tenant route slug, domain veya session claim üzerinden belirlenebilir. Server request tenant bilgisini doğrular. Client component'lara yalnız gerekli tenant metadata aktarılır. Context UI'da tenant adı gibi stable value'ları paylaşabilir. Authorization ve data query her zaman server-resolved tenant id ile çalışmalıdır.

Request Bazlı Tenant Isolation

Her request kendi tenant context'ine sahip olmalıdır. Module-level mutable variable kullanılmamalıdır. Store factory ve QueryClient factory request isolation sağlar. Data access layer tenant id olmadan query çalıştırmayı engelleyecek signature tasarımına sahip olabilir. Integration test iki concurrent tenant request'inde data karışmadığını doğrulamalıdır.

Cache Key'lerde Tenant Kimliği

TanStack Query key'inde tenant değişkeni bulunmazsa farklı tenant data'sı aynı cache entry'yi paylaşabilir. Server cache tag ve custom cache key'leri de tenant scope'u dikkate almalıdır. Public shared data ayrı key taxonomy kullanabilir. Tenant id key'e eklendiğinde invalidation da doğru scope'ta çalışır. Cache isolation güvenlik requirement olarak test edilmelidir.

Kullanıcı Değişiminde Store Reset

Aynı browser session'ında kullanıcı veya tenant değiştiğinde shared client store içindeki eski business state temizlenmelidir. Workspace selection ve draft state yeni tenant'a taşınmamalıdır. Persistence key tenant-scoped olabilir veya logout sırasında storage silinebilir. Public theme preference korunabilir. Reset policy her store için data classification'a göre belirlenmelidir.

Cross-Tenant Data Leakage'i Önleme

Cross-tenant leakage yalnız backend query hatasından oluşmaz. Client cache, persisted state, error log veya browser memory de veri sızıntısı kaynağı olabilir. Tenant değişim testinde route, query cache ve global store birlikte temizlenmelidir. Telemetry sensitive payload kaydetmemelidir. Security review state architecture'ı backend authorization kadar ciddiye almalıdır.

Persistent State Yönetimi

Persistent state browser refresh veya uygulama yeniden açılışı sonrasında korunması gereken client data için kullanılır. localStorage, sessionStorage, cookie ve IndexedDB farklı güvenlik ve kapasite özelliklerine sahiptir. Her state'i persist etmek kullanıcı deneyimini iyileştirmez, stale ve hassas veri riskini artırabilir. Stored schema zamanla değişeceği için version ve migration strategy gerekir. Persistence yalnız storage seçimi değil lifecycle ve recovery tasarımıdır.

localStorage

localStorage browser origin seviyesinde kalıcı key-value storage sağlar. Synchronous API olduğu için büyük data UI thread'i etkileyebilir. JavaScript erişebildiği için XSS durumunda içeriği okunabilir. Theme veya düşük riskli preference için kullanılabilir. Access token ve hassas müşteri verisi için güvenli vault olarak görülmemelidir.

sessionStorage

sessionStorage tab/session yaşamı boyunca data saklar. Tab kapandığında state genellikle temizlenir. Multi-tab paylaşımı localStorage'dan farklıdır. Kısa süreli draft veya wizard continuation için kullanılabilir. Security açısından JavaScript erişimi olduğu için hassas secret yine saklanmamalıdır.

Cookie

Cookie server request ile birlikte taşınabildiği için server ve client başlangıç state'ini hizalamada yararlı olabilir. HttpOnly cookie JavaScript tarafından okunamaz ve authentication token için daha güvenli model sağlayabilir. UI preference için client-readable cookie kullanılabilir. Size ve request overhead sınırlamaları vardır. SameSite, Secure ve expiration policy doğru yapılandırılmalıdır.

IndexedDB

IndexedDB daha büyük ve structured browser data için uygundur. Offline cache, local draft database veya large editor state saklanabilir. Async API localStorage'a göre main thread açısından avantajlıdır. Schema migration yine gereklidir. Hassas data storage kararı encryption ve threat model ile birlikte verilmelidir.

Hangi State Persist Edilmemelidir?

Loading flag, validation error, open modal veya request-specific state persist edilmemelidir. Access token veya highly sensitive customer data browser persistence için uygun değildir. Server-owned data çoğu zaman cache veya yeniden fetch ile daha güvenli yönetilir. Derived state yeniden hesaplanabilir. Persistence listesi whitelist mantığıyla açıkça belirlenmelidir.

Persisted State Schema Versioning

Store shape deployment'larla değiştiğinde eski browser storage yeni kodla uyumsuz olabilir. Persisted data version numarası taşımalıdır. Migration eski version'ı yeni schema'ya dönüştürür. Migration başarısız olursa güvenli default'a reset yapılmalıdır. Versioning yoksa production'da yalnız uzun süreli kullanıcıların yaşadığı zor teşhis edilen bug'lar oluşabilir.

Version

Persisted schema her breaking değişiklikte version artırabilir. Version application package version'ından bağımsız olabilir. Storage data hangi migrator'ın uygulanacağını bilir. Çok sık version bump gereksiz maintenance oluşturur. Yalnız schema compatibility değiştiğinde artırmak yeterlidir.

Migration

Migration önceki persisted state'i yeni shape'e güvenli biçimde dönüştürür. Eski alan rename veya type change burada ele alınabilir. Migration pure ve test edilebilir function olarak yazılmalıdır. Kullanıcı datası kaybolacaksa product kararı açık olmalıdır. Birden fazla eski version'dan upgrade senaryosu test edilmelidir.

Backward Compatibility

Rolling deployment veya çoklu tab senaryosunda eski ve yeni client version kısa süre birlikte yaşayabilir. Storage schema değişimi bu durumu bozabilir. Migration ve tolerant read pattern backward compatibility sağlayabilir. Cross-tab write davranışı ayrıca test edilmelidir. Çok kritik persisted data için server sync daha güvenli olabilir.

Invalid State Recovery

Storage bozuk, elle değiştirilmiş veya beklenmeyen formatta olabilir. Parse edilen data TypeScript type'ı var diye runtime güvenli sayılmamalıdır. Schema validation başarısızsa state temizlenip default değerle devam edilebilir. Kullanıcıya gerekiyorsa recovery mesajı gösterilir. Invalid state uygulamayı boot edemez hâle getirmemelidir.

State Management ve Güvenlik

Client state kullanıcı cihazında çalıştığı için güvenli server storage değildir. Browser'a gönderilen her değer kullanıcı tarafından görülebilir veya değiştirilebilir. Authorization kararı client boolean'a dayandırılmamalıdır. Sensitive token ve personal data storage seçimi threat model ile değerlendirilmelidir. Logout sonrası state ve cache temizliği security lifecycle'ın bir parçasıdır.

Sensitive Data'yı Client Store'da Tutmamak

Client store browser memory'sinde bulunur ve development tools tarafından görülebilir. Credit card detail, private token veya gereksiz PII burada tutulmamalıdır. UI'nın gerçekten ihtiyaç duyduğu minimum field client'a gönderilmelidir. Server Component sensitive data'yı server tarafında işleyebilir. Data minimization state architecture için de geçerli security prensibidir.

Token State Problemi

Access token'ı global store'da tutmak component'ların authentication detayına doğrudan bağımlı hâle gelmesine neden olabilir. Refresh sonrası persistence ihtiyacı localStorage riskini gündeme getirir. HttpOnly cookie tabanlı session birçok web uygulamasında daha güvenli seçenek olabilir. API architecture farklı token modeli gerektiriyorsa XSS ve rotation riskleri açıkça değerlendirilmelidir. Token application state değil security credential'dır.

localStorage Güvenlik Riskleri

localStorage JavaScript tarafından erişilebilir. XSS çalışan bir attacker stored token veya sensitive data'yı okuyabilir. Encryption key de aynı client içinde bulunuyorsa tek başına güçlü koruma sağlamaz. Düşük riskli preference için kullanımı makuldür. Authentication secret için threat model daha güçlü storage yaklaşımı gerektirir.

Client Authorization'ın Gerçek Güvenlik Kontrolü Olmaması

Client `canDelete` false ise button gizlenebilir, fakat attacker request'i doğrudan gönderebilir. Backend delete operation permission'ı tekrar kontrol etmelidir. Client permission state yalnız UX sağlar. Server Component da render sırasında yetkiyi doğrulayabilir. Güvenlik kararı her zaman trusted server boundary'de verilmelidir.

Logout Sonrası State ve Cache Temizliği

Logout security boundary reset'idir. Query cache, Redux slice, Zustand store ve persisted browser data user-specific alanlarda temizlenmelidir. Multi-tab logout sync düşünülmelidir. Service worker veya offline cache sensitive data tutuyorsa ayrıca reset gerekir. Sonraki kullanıcı önceki session snapshot'ına erişmemelidir.

Provider Architecture Nasıl Tasarlanmalıdır?

Provider architecture Client Component boundary'nin ne kadar genişlediğini ve state'in hangi subtree'de yaşadığını belirler. Bütün provider'ları root layout'a yığmak kolay başlangıç olsa da gereksiz global lifetime ve client bundle etkisi yaratabilir. Theme provider global gerekebilirken checkout store yalnız checkout route altında yaşayabilir. Feature-scoped ve route-scoped provider yaklaşımı state ownership'i component tree üzerinde görünür hâle getirir. Provider composition okunabilir tutulmalı ve root provider anti-pattern'ine dönüşmemelidir.

Root Provider Anti-Pattern

Redux, Zustand, QueryClient, modal, form ve feature provider'larının tamamını root'ta toplamak application'ın bütün route'larını aynı client dependencies'e bağlar. State lifetime gereksiz uzar. Route-specific data navigation sonrası kalabilir. Client bundle ve hydration alanı büyüyebilir. Global provider yalnız gerçekten global olan capability için kullanılmalıdır.

Provider'ları Mümkün Olduğunca Aşağı Taşımak

Provider gerekli en alt common ancestor'a konumlandırılabilir. Checkout state yalnız checkout layout'u altında yaşar. TanStack Query yalnız live dashboard route'unda gerekiyorsa orada açılabilir. Böylece başka sayfalar provider JavaScript'ini taşımayabilir. State scope doğal component lifecycle ile hizalanır.

Feature-Scoped Provider

Feature store sadece ilgili feature subtree tarafından kullanılabilir. Bu yapı package boundary ile aynı ownership'i yansıtır. Feature unmount olduğunda state temizlenir. Test setup daha küçük ve bağımsız olur. Cross-feature state paylaşımı gerektiğinde gerçekten global contract olup olmadığı yeniden değerlendirilir.

Route-Scoped Provider

App Router layout'ları route-specific provider için doğal yer sağlar. `/checkout` layout'u kendi Redux veya Zustand provider'ını barındırabilir. Navigation başka root branch'e geçtiğinde state yaşamı sona erebilir. Route reset logic azalır. Provider'ın layout caching davranışı route navigation ile birlikte test edilmelidir.

Nested Providers

Farklı state concern'leri nested provider olarak bir arada kullanılabilir. Theme global, QueryClient feature ve form provider component seviyesinde olabilir. Provider order dependency'si varsa açıkça dokümante edilmelidir. Aşırı nesting okunabilirliği azaltabilir. Composition utility yalnız görsel sadeleştirme yapmalı, lifecycle davranışını gizlememelidir.

Provider Composition

Provider composition ortak wrapper oluşturabilir. Ancak tüm provider'ları tek `AppProviders` içine koymak scope kararını tekrar root'a taşıyabilir. Global ve feature provider ayrımı korunmalıdır. Composition test setup'ını kolaylaştırabilir. Wrapper'ın hangi provider'ı neden içerdiği açık kalmalıdır.

Client Bundle Üzerindeki Etki

Client Provider import ettiği library ve child client dependencies'i bundle'a taşır. Provider root'a çıktıkça daha geniş route set'i aynı JavaScript maliyetini taşıyabilir. Bundle analyzer route bazında ölçüm yapmalıdır. Server-rendered route'larda gereksiz store library yüklemekten kaçınılmalıdır. Provider placement performance architecture'ın doğrudan parçasıdır.

Kurumsal State Management'ta Performans

State management performansı yalnız store library'nin benchmark skoruyla ölçülmez. Subscription granularity, selector design, Client Component alanı ve hydration maliyeti gerçek kullanıcı deneyimini belirler. Context yanlış kullanıldığında geniş re-render, Zustand yanlış selector ile fazla subscription, Redux yanlış selector ile gereksiz render üretebilir. Server-owned veriyi client'a taşımamak bundle ve hydration işini azaltır. Performance optimization önce gerçek profiler ve RUM verisiyle problemli path'i bulmalıdır.

Subscription Granularity

Component yalnız kullandığı state alanına subscribe olmalıdır. Büyük object veya tüm store subscription her değişiklikte render tetikleyebilir. Domain selector granular access sağlar. Çok fazla mikro subscription da complexity oluşturabilir. Denge gerçek component behavior'a göre belirlenmelidir.

Selector Kullanımı

Selector component'ın ihtiyacı olan minimum state'i döndürür. Derived hesaplamayı merkezileştirir. Referans olarak her seferinde yeni object döndürüyorsa equality davranışı dikkat edilmelidir. Memoization pahalı hesaplar için kullanılabilir. Selector architecture performans ve encapsulation kazancını birlikte sağlar.

Context Re-render Problemi

Context value değiştiğinde consumer component'lar yeniden render olabilir. Sık değişen büyük mutable state'i tek Context içine koymak geniş update surface oluşturur. Context value domain'lere bölünebilir veya store library selective subscription sağlayabilir. Provider value `useMemo` ile gereksiz referans değişiminden korunabilir. Ancak asıl çözüm yanlış state türünü Context'a koymamak olabilir.

Zustand Selector Optimization

Zustand component başına küçük selector kullanmayı kolaylaştırır. Object selector'larda shallow equality değerlendirilebilir. Store action ve data selection ayrı selector olarak alınabilir. Hot update path profiler ile ölçülmelidir. Premature optimization uğruna okunabilirliği bozacak custom equality zincirleri eklenmemelidir.

Redux Memoized Selectors

Redux `createSelector` derived data hesaplamalarını input state değişmediğinde tekrar çalıştırmamaya yardımcı olur. Large list filter ve aggregate işlemlerinde değerlidir. Memoization key scope ve selector instance lifecycle düşünülmelidir. Basit field access için `createSelector` gerekmeyebilir. Domain selector API performans optimizasyonunun merkezi noktası olabilir.

Gereksiz Client Component'ları Azaltmak

State management library kullanımı çoğu zaman component'ı Client Component yapar. Store yalnız küçük interactive alan için gerekiyorsa boundary aynı yerde tutulmalıdır. Parent layout ve static content Server Component kalabilir. Bu yaklaşım JavaScript bundle ve hydration işini azaltır. Client component sayısı değil, bundle'a giren gerçek dependency ve interaction yükü ölçülmelidir.

Bundle Size Ölçümü

Redux Toolkit, Zustand ve TanStack Query farklı bundle maliyetleri taşır, ancak application code ve third-party library'ler toplam sonucu belirler. Route-level bundle analyzer kullanılmalıdır. Library iki küçük component için eklendiyse maliyet görünür olur. Dynamic import uygun feature'larda kullanılabilir. Bundle size tek başına execution ve hydration maliyetini göstermediği için profiler metric'leriyle birlikte değerlendirilmelidir.

Hydration Maliyetini Ölçmek

Client Components ilk server HTML'ine event handler ve state bağlamak için hydration işi yapar. Büyük provider ağacı ve client-heavy UI main thread'i yorabilir. React Profiler ve browser performance trace hydration süresini gösterebilir. Server-first architecture bu alanı küçültür. Hydration optimization gerçek interaction readiness ve INP gibi kullanıcı metric'leriyle ilişkilendirilmelidir.

State Management Observability ve Debugging

Kurumsal state management production'da “hangi action oldu?” ve “hangi cache stale kaldı?” sorularına cevap verebilmelidir. Development DevTools önemli olsa da production telemetry ayrıca gerekir. Mutation failure, cache invalidation hatası ve workflow transition'ları domain event olarak izlenebilir. Sensitive state loglanmamalıdır. Observability state bug'larını yalnız kullanıcı ekran görüntüsü üzerinden çözme dönemini sona erdiren önemli platform capability'sidir.

Redux DevTools

Redux DevTools development sırasında action ve state timeline sağlar. Complex checkout bug'ında transition sırasını görmek kolaylaşır. Action payload içinde sensitive data tutulmamalıdır. Time travel bazı pure client workflow'larda yararlı olabilir. Production issue için aynı action isimleri telemetry event'leriyle ilişkilendirilebilir.

TanStack Query Devtools

TanStack Query Devtools query key, status, stale state ve cache içeriğini gözlemlemeyi kolaylaştırır. Invalidation çalıştı mı veya query neden refetch oldu soruları hızlı cevaplanabilir. Development ortamında güçlü debugging sağlar. Production'da direkt devtools yerine metric ve tracing kullanılabilir. Query key standardı tool'un okunabilirliğini doğrudan etkiler.

Action Logging

Critical Redux veya Zustand action'ları structured log formatında izlenebilir. Her keystroke loglanmamalıdır. Business workflow transition'ları, reset ve failure recovery event'leri daha anlamlıdır. User id yerine privacy-safe correlation identifier kullanılabilir. Action logging incident sırasında state geçmişini yeniden kurmaya yardımcı olur.

State Transition Tracing

Distributed trace içinde frontend workflow event'leri backend mutation ile ilişkilendirilebilir. Checkout submit action correlation id ile API request'e bağlanabilir. Failure'ın UI transition mı backend response mu olduğu ayırt edilir. Client telemetry sampling uygulanabilir. Transition tracing büyük ve kritik kullanıcı journey'lerinde özellikle değerlidir.

Mutation Failure Monitoring

Server Action, RTK Query veya TanStack Query mutation failure oranları izlenmelidir. Error type validation, permission veya infrastructure olarak sınıflandırılabilir. Retry sonrası başarı ayrı metric olabilir. Optimistic rollback sayısı UX problemini gösterebilir. Error monitoring state architecture'ın reliability katmanıdır.

Cache Invalidation Hatalarını İzlemek

Invalidation unutulması doğrudan exception üretmeyebilir, kullanıcı yalnız eski veri görür. Mutation sonrası expected query refetch metric'i veya version mismatch telemetry yardımcı olabilir. Server ve client cache policy testlerle korunmalıdır. Support ticket'larda stale data pattern'i ayrı kategori olabilir. Cache correctness görünmez olduğu için proactive gözlem gerekir.

Production Telemetry

Production telemetry action count, mutation latency, query retry ve hydration error gibi signal'ları toplayabilir. Her state value loglanmamalıdır. Privacy ve maliyet nedeniyle structured low-cardinality event tercih edilir. Feature version ve route metadata incident correlation sağlar. Dashboard yalnız teknik metric değil business-critical workflow success oranını da göstermelidir.

Kurumsal State Management Test Stratejisi

State management testi yalnız reducer unit testlerinden ibaret değildir. SSR, hydration, request isolation, navigation ve persistence migration gibi Next.js'e özgü failure mode'ları ayrıca test etmek gerekir. Server ve client source of truth senkronizasyonu integration testlerle doğrulanmalıdır. Optimistic update ve cache invalidation senaryoları özellikle production bug'larına açıktır. Test stratejisi state sınıflandırmasına göre farklı katmanlarda doğru güvenceyi sağlar.

Reducer ve Action Unit Testleri

Redux reducer aynı input state ve action için beklenen next state'i üretmelidir. Boundary ve invalid transition senaryoları test edilir. Action creator payload type compile-time güveni sağlasa da business validation ayrıca gerekebilir. Pure reducer testleri hızlıdır. Her UI click'in reducer testini yazmak yerine domain transition'ları önceliklendirilmelidir.

Zustand Store Testleri

Store factory her test için temiz instance üretir. Action sonrası state değişimi doğrudan doğrulanabilir. Persistence middleware varsa mock storage kullanılabilir. Reset behavior test edilmelidir. Component integration test store selector kullanımını ayrıca doğrular.

Selector Testleri

Derived business logic selector içinde ise bağımsız test etmek önemlidir. Farklı base state kombinasyonlarında doğru sonucu üretmelidir. Memoization behavior performance-critical selector için ayrıca kontrol edilebilir. Internal store shape değişiminde public selector contract sabit kalmalıdır. Selector testleri component testlerinde tekrar logic kurma ihtiyacını azaltır.

Query Cache Testleri

TanStack Query testinde her case için fresh QueryClient kullanılmalıdır. Query function success ve error behavior test edilir. Invalidation sonrası query stale veya refetch durumuna geçiyor mu doğrulanır. Retry testinde fake timer kullanılabilir. QueryClient global test instance olarak paylaşılmamalıdır.

Optimistic Update ve Rollback Testleri

Mutation başlamadan optimistic state görünmelidir. Server failure sonrası eski snapshot geri dönmelidir. Concurrent mutation scenario out-of-order response ile test edilir. Success sonrası canonical server response cache'e uygulanmalıdır. UI error state kullanıcıya doğru feedback vermelidir.

SSR Testleri

Server render kullanıcıya doğru initial state üretmeli ve browser-only API'ye erişmemelidir. Request-specific data farklı request'lerde izole test edilir. Auth ve tenant scenario'ları önceliklidir. Server output client initial state ile uyumlu olmalıdır. SSR test production caching behavior'a yakın environment kullanmalıdır.

Hydration Testleri

Server HTML client tarafından warning olmadan hydrate edilmelidir. Persisted store boş ve dolu storage ile test edilir. Date, locale veya browser-only state mismatch senaryoları kontrol edilir. Hydration error console output CI'da failure olarak ele alınabilir. Test yalnız snapshot değil gerçek hydrate flow çalıştırmalıdır.

Request Isolation Testleri

Aynı anda iki user veya tenant request'i çalıştırılır. Store ve QueryClient state'inin birbirine karışmadığı doğrulanır. Test özellikle module singleton hatalarını yakalar. User A'nın initial state'i User B response'unda görünmemelidir. Security regression suite içinde bu senaryo tutulmalıdır.

Route Navigation Testleri

Client navigation store lifetime davranışını test eder. Route A state'i Route B'ye taşınıyor mu kontrol edilir. Back navigation URL state'i doğru restore etmelidir. Provider scope beklenen reset'i üretmelidir. E2E test user journey üzerinden gerçek App Router navigation çalıştırmalıdır.

Persistence Migration Testleri

Eski storage fixture yeni version store'a yüklenir. Migration doğru data shape üretmelidir. Corrupt data safe fallback ile resetlenmelidir. Birkaç eski version migration path'i ayrı test edilmelidir. Production'da kullanıcı storage'ını tamamen silmek son çare olmalıdır.

Kurumsal Monorepo'larda State Management

Monorepo shared state logic'i paket hâline getirmeyi kolaylaştırır, ancak tek global store package yaratmak her feature'ı aynı runtime'a bağlayabilir. Domain package'ları kendi public action ve selector API'lerini sunabilir. UI state business state'ten ayrılmalıdır. Internal store shape package dışına sızdırılmazsa refactoring daha güvenli olur. Dependency rule'ları cross-domain import ve circular state bağımlılığını engellemelidir.

Shared Store Package Oluşturulmalı mı?

Bütün application için tek `shared-store` package ilk bakışta pratik görünebilir. Zamanla her feature buraya state eklediğinde ownership belirsizleşir. Gerçekten cross-application client state varsa shared package düşünülebilir. Çoğu business domain kendi package'ında store logic tutmalıdır. Shared package minimum infrastructure helper ve type ile sınırlanabilir.

Domain Package'ları

`checkout`, `identity` veya `workspace` package'ı kendi state logic'ini barındırabilir. Public exports action, selector ve provider ile sınırlı tutulur. Başka domain internal slice dosyasını import etmez. Package testleri bağımsız çalışır. Team ownership monorepo codeowner ile desteklenebilir.

UI State ile Business State'i Ayırmak

Sidebar collapse state ile checkout payment transition aynı store concern değildir. UI package görsel interaction state'ini yönetebilir. Business domain daha explicit action ve test kurallarına sahip olur. İki state türünü tek generic `appStore` altında toplamak sınırları siler. Ayrım dependency direction ve persistence kararını da kolaylaştırır.

Public Store API

Package component'lara raw store object yerine typed selector ve action hook sunabilir. Internal state shape private kalır. Version değişiminde consumer code daha az etkilenir. Public API semantic business isimleri kullanmalıdır. Bu yaklaşım package ownership ve migration sürecini kolaylaştırır.

Internal Store Shape'i Gizlemek

Consumer `state.checkout.internal.forms.step2.fieldX` gibi path'lere bağımlı olmamalıdır. Domain selector bu bilgiyi soyutlar. Internal normalization veya refactor public component'ı kırmaz. Test fixture'ları da internal shape yerine factory kullanabilir. Encapsulation state architecture'ın uzun ömürlü olmasını sağlar.

Package Boundary ve Dependency Rules

Domain A doğrudan Domain B store internals'ını import ederse monorepo distributed global store'a dönüşür. Lint veya build rule cross-domain dependency'yi kontrol edebilir. Coordination event, shared contract veya application orchestration üzerinden yapılmalıdır. Circular import erken yakalanmalıdır. Dependency graph architecture review'ın ölçülebilir girdisi olabilir.

Micro-Frontend Mimarisinde State Management

Micro-frontend yapısında tek global store bütün uygulamaları aynı runtime ve release contract'ına bağlayabilir. Her domain kendi state'inin sahibi olmalıdır. Shared state minimum tutulmalı ve mümkünse URL, event veya versioned contract üzerinden koordine edilmelidir. Store object'ini runtime global üzerinden paylaşmak independent deployment avantajını azaltır. Micro-frontend state tasarımı teknik paylaşım kadar organizational ownership problemidir.

Tek Global Store Kullanmanın Riskleri

Tüm micro-frontend'ler aynı Redux store'a bağlanırsa slice ve action version uyumu zorunlu olur. Bir uygulamanın deploy'u diğerini etkileyebilir. Store schema merkezi release bottleneck'e dönüşür. Runtime coupling independent deployment hedefiyle çelişir. Shared global store yalnız gerçekten ortak küçük contract için düşünülmelidir.

Domain Ownership

Her micro-frontend kendi business state'ini yönetir. Cart micro-frontend cart interaction'ın, account identity UI'nın sahibi olur. Server business data yine ilgili backend domain tarafından sahiplenilir. Cross-domain data explicit API üzerinden alınır. Ownership sınırı deploy ve on-call sorumluluğuyla hizalanmalıdır.

Shared State Minimumda Tutulmalı mı?

Evet, ortak state ne kadar küçükse independent evolution o kadar kolaydır. Locale, theme veya authenticated user summary gibi değerler paylaşılabilir. Full business entity graph paylaşmak coupling yaratır. Shared state contract versioned olmalıdır. Her yeni ortak field architecture review gerektirebilir.

URL Üzerinden Coordination

Search, tab veya selected entity id URL'de taşınabilir. Micro-frontend'ler aynı URL contract'ını okuyarak coordination sağlar. Merkezi store gerekmeyebilir. Deep link ve browser history doğal çalışır. URL contract değişikliği versioned route policy ile yönetilmelidir.

Event-Based Communication

Micro-frontend'ler `cartUpdated` veya `workspaceChanged` gibi event contract üzerinden haberleşebilir. Event payload minimum tutulmalıdır. Event replay veya ordering ihtiyacı varsa basit browser event modeli yetersiz kalabilir. Business source of truth yine server'da kalır. Event contract version ve ownership bilgisi taşımalıdır.

Versioned Contracts

Bağımsız deploy edilen frontend'ler aynı anda farklı contract version kullanabilir. Shared package veya runtime event schema backward compatible geliştirilmelidir. Breaking change staged rollout gerektirir. Consumer telemetry hangi version'ın hâlâ kullanıldığını gösterebilir. Versioned contract micro-frontend bağımsızlığının temelidir.

Legacy Redux Projesini Modern Next.js Mimarine Taşımak

Legacy Redux projesinde en iyi migration yaklaşımı store'u bir gecede silmek değildir. Önce state inventory çıkarılıp server, URL, local UI ve gerçek client business state ayrılır. Server response slice'ları TanStack Query veya Server Components'a taşınabilir. Local state component'a geri getirilebilir. Complex client workflow Redux Toolkit'te kalırken migration kademeli ilerler.

Önce State Inventory Çıkarmak

Her slice'ın hangi state türünü taşıdığı listelenir. Server data, local UI ve derived state farklı etiketlenir. Kullanılmayan slice ve action'lar telemetry veya code search ile bulunur. Persistence ve route dependency kayıt altına alınır. Bu inventory migration backlog'un gerçek kapsamını gösterir.

Server State'i Redux'tan Çıkarmak

API response cache olarak kullanılan slice'lar ilk adaydır. Read path Server Component veya query library'ye taşınabilir. Mutation sonrası invalidation yeni cache modeline göre kurulur. Component consumer API selector facade üzerinden geçiş döneminde korunabilir. Aynı data iki sistemde uzun süre tutulmamalıdır.

URL State'i Store'dan Çıkarmak

Filter, search ve pagination slice'ları search params'e taşınabilir. Component hook URL'den state üretir. Back ve bookmark behavior otomatik kazanılır. Migration sırasında store ile URL çift source oluşturulmamalıdır. Tek route üzerinde pilot yapıp pattern standardize edilebilir.

Local UI State'i Component'a Geri Taşımak

Modal ve dropdown state store'dan kaldırılıp ilgili component'a taşınabilir. Global action sayısı azalır. Test setup sadeleşir. Route navigation stale state problemi ortadan kalkabilir. Sadece gerçekten cross-component kullanılan UI state shared store'da bırakılır.

Complex Client Workflow'ları Redux'ta Bırakmak

Migration'ın amacı Redux'u tamamen silmek olmamalıdır. Checkout veya complex editor gibi Redux'un değer kattığı alan korunabilir. Slice modern Redux Toolkit pattern'lerine güncellenebilir. Server data ayrı katmana çıkarıldığında Redux store daha küçük ve amacına uygun hâle gelir. Bu kademeli yaklaşım risk ve delivery süresini dengeler.

TanStack Query'ye Kademeli Migration

Bir domain query set'i pilot olarak TanStack Query'ye taşınabilir. Query key ve invalidation convention doğrulanır. Eski selector consumer'ları adapter ile geçici desteklenebilir. Cache duplication kısa tutulmalıdır. Migration metric olarak code complexity ve stale data bug sayısı takip edilebilir.

Consumer API'lerini Sabit Tutmak

Component'lar raw Redux shape'e bağlı değilse migration kolaylaşır. Domain hook veya selector API arkasındaki implementation değiştirilebilir. `useProducts()` önce Redux, sonra TanStack Query kullanabilir. Consumer code aynı kalır. Encapsulation geçmişte kurulmamışsa migration ilk adımında facade eklemek faydalı olabilir.

Big Bang Rewrite'dan Kaçınmak

Bütün state architecture'ı aynı release'te değiştirmek regression riskini büyütür. Domain veya route bazlı incremental migration daha güvenlidir. Eski ve yeni telemetry yan yana karşılaştırılabilir. Rollback daha kolay olur. Architecture modernization ürün geliştirmeyi aylarca durduran ayrı proje hâline getirilmemelidir.

Pages Router'dan App Router'a State Migration

Pages Router'dan App Router'a geçiş yalnız dosya sistemi migration'ı değildir. `getServerSideProps` ile client store initialization alışkanlıkları Server Components ve Server Actions ışığında yeniden değerlendirilmelidir. Root provider sayısı küçültülebilir. Request state global store'dan server request context'e taşınabilir. Cache ve revalidation stratejisi yeni architecture'a göre yeniden tasarlanmalıdır.

getServerSideProps Alışkanlıkları

Pages Router'da page-level data fetching tek merkezde toplanıyordu. App Router'da ilgili Server Component kendi datasını fetch edebilir. Bütün initial data'yı tek Redux hydration object'ine toplamak artık gerekli değildir. Data ownership component ve domain sınırına yaklaşır. Migration eski pattern'i yeni klasöre kopyalamak yerine architecture fırsatı olarak görülmelidir.

Client Fetching'i Server Components'a Taşımak

Initial page data `useEffect` veya Redux thunk ile client'ta fetch ediliyorsa Server Component'a taşınabilir. Kullanıcı daha erken content görür ve client loading state azalır. Live refresh gereken data client query layer'da kalabilir. Her fetch server'a taşınmamalı, interaction modeline göre karar verilmelidir. Migration route bazında performans ölçümüyle doğrulanmalıdır.

Root Provider'ları Küçültmek

Pages Router `_app` içinde bütün provider'lar global olmak zorundaymış gibi kurulmuş olabilir. App Router nested layout ile provider scope küçültmeye imkân verir. Checkout veya dashboard provider yalnız ilgili route'a taşınabilir. Client bundle ve state lifetime azalır. Provider graph migration checklist'inde ayrı kalem olarak incelenmelidir.

Request State'i Global Store'dan Çıkarmak

User locale, tenant veya server-derived feature config global Redux store'a konmuş olabilir. App Router request API ve Server Components bu bilgiyi doğrudan server'da kullanabilir. Client'a yalnız gerekli snapshot aktarılır. Store request state taşıma sorumluluğundan kurtulur. Security ve isolation modeli daha anlaşılır hâle gelir.

Server Actions'a Geçiş

Basit form mutation için ayrı API endpoint ve Redux thunk zinciri gerekmeyebilir. Server Action server-side validation ve mutation'ı doğrudan çalıştırabilir. Revalidation mutation sonrası aynı akışta yapılabilir. Client optimistic UX gerekiyorsa ek state kullanılabilir. Migration her endpoint'i Server Action'a çevirmek değil uygun mutation'ları seçmek anlamına gelir.

Cache ve Revalidation Stratejisini Yeniden Tasarlamak

Pages Router'daki fetch davranışı App Router cache modeliyle aynı değildir. Hangi data cache'leniyor, hangi tag veya path mutation sonrası yenileniyor açıkça belirlenmelidir. Client query cache varsa server cache ile ilişki tanımlanmalıdır. Double caching stale data riskini artırabilir. Migration testleri mutation sonrası navigation ve refresh davranışını kapsamalıdır.

Next.js State Management Anti-Pattern'leri

State anti-pattern'lerinin çoğu uygun state türünü yanlış katmana yerleştirmekten doğar. Her şeyi Redux'a veya Zustand'a koymak farklı ownership türlerini tek modele zorlar. API response kopyaları duplicate source oluşturur. Request-specific data singleton store'da güvenlik riski yaratır. Derived ve persisted state konusunda gereksiz tekrar store'u büyütür ve davranışı tahmin etmeyi zorlaştırır.

Her Şeyi Redux'a Koymak

Redux güçlü olduğu için bütün data'nın burada yaşaması gerekmez. URL state, server data ve local modal state farklı doğal sahiplik alanlarına sahiptir. Mega store route ve server architecture'dan bağımsız ikinci application modeline dönüşür. Selector ve invalidation yükü büyür. Redux yalnız global mutable client business state'e odaklandığında daha değerli olur.

Her Şeyi Zustand'a Koymak

Zustand'ın düşük ceremony'si state eklemeyi çok kolaylaştırır. Bu kolaylık server response, URL parametreleri ve local state'in store'a taşınmasına yol açabilir. Global module store Next.js server'da request riskleri oluşturur. Store sayısı arttığında ownership convention gerekir. Sadelik architecture sınırsızlığı anlamına gelmemelidir.

API Response'larını Global Store'a Kopyalamak

Her query sonucu store'a kopyalandığında loading, stale ve refetch logic manuel yönetilir. Server cache ile browser store birbirinden ayrışabilir. TanStack Query veya RTK Query bu problem için daha uygun abstraction sağlar. Server-only ekranlarda client cache bile gerekmeyebilir. Store yalnız gerçekten client business mutation'ına ihtiyaç duyan data için kullanılmalıdır.

URL'ye Ait State'i Store'da Tutmak

Filter ve pagination global store'da tutulduğunda deep link ve back button bozulabilir. Refresh state'i kaybedebilir veya persistence eklemek gerekir. URL zaten bu problemi doğal olarak çözer. Store ve URL ikisi birden kullanılırsa sync code oluşur. Navigation state için URL ilk tercih olmalıdır.

RootLayout'a Dev Bir Client Provider Koymak

Root layout bütün provider'ları sardığında static route'lar bile client dependency taşıyabilir. Route-specific state gereğinden uzun yaşar. Bundle ve hydration maliyeti genişler. Provider'lar ilgili feature veya route seviyesine taşınabilir. Global capability ile convenience provider birbirinden ayrılmalıdır.

Server ve Client'ta İki Source of Truth Oluşturmak

Server product data bir değer gösterirken client store eski kopyayı tutabilir. Mutation sonrası hangisinin güncelleneceği belirsizleşir. Client store yalnız temporary draft veya optimistic representation taşıyabilir. Canonical source server olarak kalmalıdır. Reconciliation ve invalidation explicit tasarlanmalıdır.

Request-Specific Veriyi Singleton Store'da Tutmak

User id, tenant veya session module singleton state içine yazılmamalıdır. Concurrent request farklı kullanıcı data'sını paylaşabilir. Request-scoped factory pattern kullanılmalıdır. Server Components global mutable store okumamalıdır. Bu anti-pattern security review'da yüksek risk olarak ele alınmalıdır.

Derived State'i Gereksiz Yere Saklamak

Base state'ten hesaplanabilen result ayrıca store'a yazıldığında sync yükü oluşur. Bir action base value'yu güncelleyip derived value'yu unutabilir. Selector hesaplama bu problemi ortadan kaldırır. Memoization pahalı hesaplarda kullanılabilir. Store yalnız authoritative mutable değerleri taşımalıdır.

Persist Edilmemesi Gereken State'i Persist Etmek

Loading ve error state storage'da kaldığında refresh sonrası anlamsız UI oluşabilir. Sensitive data security riski yaratır. Server cache data localStorage içinde stale kalabilir. Persistence whitelist ile sınırlı tutulmalıdır. Her persisted field için “neden refresh sonrası korunmalı?” sorusunun cevabı bulunmalıdır.

Mutation Sonrası Cache Invalidation'ı Unutmak

Database update başarılı olabilir fakat UI eski cache göstermeye devam edebilir. Server path, server tag ve client query cache ayrı katmanlarda etkilenebilir. Mutation handler invalidation planını bilmelidir. Test success sonrası fresh data'yı doğrulamalıdır. Cache correctness business operation'ın tamamlanma kriterlerinden biridir.

Kurumsal Next.js Projesi İçin State Management Karar Ağacı

Karar ağacı state tartışmasını hızlı ve tekrarlanabilir hâle getirir. İlk soru verinin server'a mı, URL'ye mi, local component'a mı yoksa shared browser workflow'a mı ait olduğudur. Bu ayrım yapıldıktan sonra araç seçimi doğal olarak daralır. Next.js'te State Management: Kurumsal Ölçekli Çözümler yaklaşımında aynı proje içinde Server Components, URL, useState, Zustand, Redux Toolkit ve TanStack Query birlikte bulunabilir. Amaç tek library standardı değil, her state sınıfına doğru ownership modelini vermektir.

Veri Server'a mı Ait? → Server Component

Database veya backend API authoritative source ise önce Server Component değerlendirilmelidir. Secret ve request context server'da kalır. Client yalnız gerekli data snapshot'ını alır. Live browser refetch gerekiyorsa ayrıca query cache eklenebilir. Server-owned data'nın varsayılan adresi global browser store olmamalıdır.

URL ile Paylaşılmalı mı? → searchParams

Filter, search, pagination veya active view link olarak anlamlıysa URL'ye taşınmalıdır. Back ve bookmark behavior otomatik kazanılır. Server Component query parametreye göre data fetch edebilir. Client filter yalnız URL update eder. Global store senkronizasyonu ortadan kalkar.

Tek Component'a mı Ait? → useState / useReducer

State tek component veya küçük feature içinde yaşıyorsa local hook en düşük maliyetli çözümdür. Complex local transition için reducer kullanılabilir. Global store eklemek gereksiz dependency yaratır. Component unmount state reset sağlar. State paylaşımı gerçek ihtiyaç olduğunda scope genişletilir.

Küçük ve Stabil Subtree State mi? → Context

Theme veya locale gibi stabil value için Context yeterlidir. Provider ilgili subtree'de tutulur. Sık değişen büyük mutable state Context'a yüklenmez. Consumer sayısı ve render behavior profiler ile kontrol edilebilir. Context global store alternatifi değil dependency sharing primitive'idir.

Shared Browser State mi? → Zustand

Birden fazla client component aynı browser-owned mutable state'i paylaşıyorsa Zustand güçlü adaydır. Store request-safe provider pattern ile oluşturulur. Selector granularity korunur. Server data store'a kopyalanmaz. Persistence gerekirse version ve hydration planı eklenir.

Karmaşık ve Denetlenebilir Business State mi? → Redux Toolkit

Çok sayıda action, domain ve workflow transition varsa Redux Toolkit convention sağlar. DevTools ve middleware debugging'i güçlendirir. Request başına store factory App Router için uygulanır. RSC store'u doğrudan kullanmaz. Business state server data cache'inden ayrı tutulur.

Async Server Cache mi? → TanStack Query / RTK Query

Browser tarafında refetch, staleTime, retry ve optimistic mutation gerekiyorsa query library kullanılabilir. Redux standardı varsa RTK Query değerlendirilebilir. Bağımsız server cache için TanStack Query güçlü seçenektir. Server Component initial prefetch ile client cache birleştirilebilir. Query cache UI state store'u değildir.

Explicit Workflow mu? → State Machine

Transition kuralları state değerinden daha önemliyse state machine tercih edilebilir. Checkout ve approval flow bunun tipik örneğidir. Impossible state kombinasyonları azalır. Guard ve event transition testleri açık yazılır. Machine Redux veya Zustand ile birlikte de kullanılabilir.

Örnek Kurumsal State Architecture

Pratik bir kurumsal architecture farklı state türlerini farklı katmanlarda tutar. Identity server'da, catalog server cache'te, search URL'de, modal local state'te ve workspace UI Zustand'da yaşayabilir. Checkout Redux Toolkit veya state machine ile, live dashboard TanStack Query ile yönetilebilir. Form mutation Server Action kullanabilir. Diyarbakır Yazılım Topluluğu'nun farklı yazılım projelerine ilişkin çalışmalarını https://www.diyarbakiryazilim.com.tr/projects adresinden incelemek bu tür mimari kararların uygulama bağlamında nasıl ele alınabileceğine dair ek fikir sağlayabilir.

Identity ve Session → Server

Authentication source of truth server session'dır. Server Component request sırasında identity'yi doğrular. Client'a yalnız gereken user snapshot aktarılır. Permission check backend'de tekrarlanır. Logout client cache reset ile tamamlanır.

Product Catalog → Server Cache

Catalog read-heavy ve birçok kullanıcı için shared olabilir. Server fetch cache ve tag invalidation kullanılabilir. Admin mutation sonrası catalog tag revalidate edilir. Client canlı filtering yapacaksa küçük snapshot kullanılabilir. Global Redux catalog kopyası zorunlu değildir.

Search Filters → URL

Search query ve filter URL search params içinde tutulur. Kullanıcı linki paylaşabilir. Server Component parametre üzerinden catalog query çalıştırır. Back navigation doğru state'i döndürür. Store ve URL sync kodu gerekmez.

Modal ve Dropdown → Local State

Modal açık mı bilgisi tek component tree'ye aittir. `useState` yeterlidir. Route değiştiğinde natural reset olur. Global store action listesi büyümez. Yalnız global modal orchestration gerçek gereksinimse scope genişletilir.

Sidebar ve Workspace UI → Zustand

Sidebar width ve workspace visual preference birden fazla client component tarafından kullanılabilir. Zustand selector tabanlı shared browser state sağlar. Preference düşük riskliyse persist edilebilir. Store factory provider scope'ta oluşturulur. Tenant değişiminde state reset edilir.

Checkout Workflow → Redux Toolkit / State Machine

Checkout transition'ları explicit ve test edilebilir olmalıdır. Redux action veya machine event shipping ve payment flow'u yönetebilir. Server mutation her adımda authoritative validation yapar. Sensitive payment detail store'da tutulmaz. Completion sonrası cart ve checkout state reset edilir.

Live Dashboard → TanStack Query

Dashboard data server tarafından sık değişebilir. TanStack Query background refetch ve stale policy sağlar. Server initial prefetch first render'ı hızlandırır. Query key tenant ve filter bilgisini içerir. Mutation sonrası ilgili widget cache'i hedefli invalidatedilir.

Form Mutation → Server Action

Basit enterprise form Server Action üzerinden submit edilebilir. Server validation ve authorization aynı boundary'de yapılır. Success sonrası server cache revalidate edilir. Client pending state local hook ile yönetilebilir. Global mutation store gerekmez.

Cache Invalidation → Server + Client Policy

Mutation hangi server tag/path ve client query key'lerini etkilediğini bilmelidir. Policy domain service veya shared utility içinde standardize edilebilir. Server-only ekran client invalidation gerektirmez. Live dashboard iki cache katmanını birlikte güncelleyebilir. Test mutation sonrası bütün visible consumer'ların fresh data gördüğünü doğrular.

Kurumsal State Management İçin Definition of Done

State feature tamamlandı kabul edilmeden ownership, source of truth ve request isolation açık olmalıdır. Hydration ve cache invalidation test edilmelidir. Persistence varsa migration planı bulunmalıdır. Observability ve client bundle etkisi review edilmelidir. Definition of Done bu kontrolleri bireysel geliştirici hafızasından çıkarıp ekip standardına dönüştürür.

State Owner Tanımlandı mı?

Her state domain veya feature owner'a sahip olmalıdır. Owner source of truth ve lifecycle kararından sorumludur. Shared store sahipsiz common alan olmamalıdır. API catalog veya architecture document ownership'i gösterebilir. Organizasyon değiştiğinde ownership güncellenmelidir.

Source of Truth Tek mi?

Aynı business data server cache ve client store'da bağımsız gerçekler hâline gelmemelidir. Client snapshot'ın authoritative olmadığı açık olmalıdır. Derived state ayrıca saklanmamalıdır. URL state tek kaynaktan okunmalıdır. Review duplicate source riskini özellikle kontrol etmelidir.

Request Isolation Sağlandı mı?

Redux, Zustand ve QueryClient server tarafında request-safe instance kullanmalıdır. Tenant ve user state concurrent request testinden geçmelidir. Module singleton içinde mutable request data bulunmamalıdır. Server Components global store okumamalıdır. Isolation security acceptance kriteridir.

Hydration Güvenli mi?

Server ve client initial render aynı state'i üretmelidir. localStorage veya browser-only data mismatch yaratmamalıdır. Persisted store hydration flow test edilir. Console hydration warning CI'da yakalanabilir. Kullanıcı flicker görmemelidir.

Cache Invalidation Tanımlandı mı?

Her mutation etkilenen server ve client cache'i bilir. Tag, path veya query key policy domain bazında standardize edilmiştir. Success sonrası stale UI kalmamalıdır. Çok geniş invalidation gereksiz network üretmemelidir. Integration test fresh data'yı doğrular.

Persistence Gerekliyse Migration Var mı?

Persisted state version bilgisi taşımalıdır. Yeni schema eski data'yı migrate edebilmelidir. Invalid data safe fallback ile temizlenir. Sensitive field storage'a yazılmaz. Migration test fixture'ları CI'da çalışır.

Testleri Yazıldı mı?

State logic unit test, integration ve gerektiğinde e2e seviyesinde doğrulanmalıdır. Request isolation ve navigation testleri Next.js için özellikle önemlidir. Optimistic update failure path test edilmelidir. Hydration ve persistence migration atlanmamalıdır. Test coverage business risk üzerinden önceliklendirilmelidir.

Observability Mevcut mu?

Critical workflow action ve mutation failure production'da görünür olmalıdır. Query invalidation sorunları teşhis edilebilmelidir. Sensitive state loglanmamalıdır. Correlation id frontend ve backend event'lerini bağlayabilir. Dashboard action alınabilir metric'ler göstermelidir.

Client Bundle Etkisi Ölçüldü mü?

Yeni state library veya provider route bundle'ını ne kadar büyüttü ölçülmelidir. Gereksiz root Client Component oluşup oluşmadığı kontrol edilir. Hydration ve INP metric'leri production'da izlenir. Küçük feature için büyük runtime eklenmemelidir. Bundle architecture kararının görünür maliyetidir.

Sık Sorulan Sorular

Next.js state management konusunda en sık karşılaşılan sorular genellikle Redux'un gerekli olup olmadığı, Zustand store'un nasıl oluşturulacağı ve server state'in nerede yaşaması gerektiği etrafında toplanır. App Router ile tek global client store merkezli eski React alışkanlıkları önemli ölçüde yeniden değerlendirilmelidir. Server Components, URL state ve query cache doğru kullanıldığında global store ihtiyacı küçülür. Redux Toolkit veya Zustand gerektiğinde güçlü araçlardır, fakat her data türünün doğal sahibi değildir. Aşağıdaki cevaplar kurumsal karar verirken en sık karşılaşılan noktaları özetler.

Next.js için Redux gerekli mi?

Hayır, Next.js uygulaması çalışmak için Redux'a ihtiyaç duymaz. Server Components, URL state, `useState`, Context ve Server Actions birçok state problemini zaten çözebilir. Redux Toolkit complex shared client business state ve büyük ekip convention'ı gerektiğinde değerlidir. Server data'yı Redux'a otomatik taşımak gerekmez. Redux gerekliliği uygulamanın workflow ve organizasyon ihtiyacına göre belirlenmelidir.

Next.js'te Zustand mı Redux Toolkit mi kullanılmalı?

Küçük ve orta büyüklükte shared browser state için Zustand daha düşük ceremony sunabilir. Complex business workflow, audit ve çok büyük ekip standardı için Redux Toolkit avantajlı olabilir. Her iki library App Router'da request isolation pattern'ine dikkat etmelidir. Server state query veya Server Component katmanında tutulabilir. Seçim state türü ve ekip governance ihtiyacına göre yapılmalıdır.

Server Components ile Redux kullanılabilir mi?

Redux store Client Component tarafında kullanılmalıdır. Server Components React Redux context veya hook kullanmamalıdır. Server data kendi source'undan alınır ve gerekirse Client Provider'a initial prop gönderilir. Redux store browser-owned mutable state'i yönetir. Bu sınır request isolation ve cache architecture'ını korur.

Zustand store Next.js'te global oluşturulabilir mi?

Browser-only SPA mantığında global store normal olabilir, ancak Next.js server rendering ortamında module-level request data paylaşmak risklidir. Resmî Next.js setup guidance request başına store creation önerir. Store factory ve Context Provider kullanmak güvenli pattern'dir. RSC store'u doğrudan okumamalıdır. Client tarafında provider içindeki instance kendi subtree'si için global davranabilir.

TanStack Query, Zustand'ın yerini alır mı?

Hayır, iki araç farklı state türlerini hedefler. TanStack Query asynchronous server state cache'i yönetir. Zustand browser-owned shared mutable state için kullanılır. Live dashboard query data TanStack Query'de, sidebar state Zustand'da bulunabilir. Aynı projede birlikte kullanımları oldukça doğaldır.

TanStack Query, Redux'un yerini alır mı?

Server response cache için Redux slice kullanılıyorsa TanStack Query bu kısmın yerini alabilir. Complex client business workflow ise Redux Toolkit'te kalabilir. Bu nedenle bütün Redux kullanımının otomatik alternatifi değildir. State inventory hangi slice'ın server data, hangisinin client business state olduğunu göstermelidir. Migration domain bazında yapılmalıdır.

Next.js'te server state nerede tutulmalı?

Server-owned data mümkün olduğunda Server Component, server cache veya uygun data access layer üzerinden yönetilmelidir. Browser'da canlı refetch gerekirse TanStack Query veya RTK Query kullanılabilir. Global client store authoritative server data kaynağı olmamalıdır. Mutation sonrası server ve client cache invalidation açık tasarlanmalıdır. Source of truth backend olarak kalmalıdır.

URL state neden global store'dan daha iyi olabilir?

URL shareable, bookmarkable ve browser history ile uyumludur. Filter, pagination ve sort bu özelliklere ihtiyaç duyar. Global store aynı davranışları ayrıca implement etmek zorunda kalır. Refresh ve deep link URL'de doğal çalışır. Sensitive veya çok büyük state dışında navigation state için güçlü varsayılandır.

Authentication state Redux/Zustand'da tutulmalı mı?

User snapshot veya UI convenience state store'da tutulabilir. Gerçek authentication source of truth server olmalıdır. Permission backend'de tekrar doğrulanır. Access token storage security modeline göre server cookie gibi daha güvenli çözüm kullanılabilir. Logout store ve query cache temizliğini tetiklemelidir.

Redux Toolkit kurumsal projeler için hâlâ mantıklı mı?

Evet, özellikle büyük ekip convention'ı, explicit state transition ve güçlü debugging ihtiyacı varsa mantıklıdır. App Router ile kullanım pattern'i klasik SPA'den farklıdır. Request-safe store ve Client Provider uygulanmalıdır. Server state store'a gereksiz taşınmamalıdır. Redux Toolkit'in değeri karmaşık client business state'i standardize etmesindedir.

RTK Query mi TanStack Query mi tercih edilmeli?

Redux Toolkit zaten application standardıysa RTK Query doğal entegrasyon sağlayabilir. Bağımsız server state katmanı isteyen ekip TanStack Query değerlendirebilir. App Router server prefetch ve hydration ihtiyacı seçimde önemlidir. Query key ve invalidation architecture her iki araçta da kritik olmaya devam eder. Kurum tek default belirleyip gerçek istisnaları kontrollü yönetebilir.

Next.js'te hydration hataları state management'tan kaynaklanabilir mi?

Evet, server ve client ilk render farklı state kullanırsa hydration mismatch oluşabilir. localStorage veya random browser-only value yaygın nedenlerdir. Store initial state iki tarafta aynı olmalıdır. Persisted data hydration sonrasında kontrollü uygulanabilir. Integration test bu hataları production öncesinde yakalamalıdır.

App Router'da request başına store neden önemlidir?

Next.js server aynı anda birden fazla kullanıcı request'i işleyebilir. Shared mutable singleton store request verisini birbirine karıştırabilir. User ve tenant leakage güvenlik problemi yaratır. Store factory her request için ayrı instance sağlar. Redux Toolkit ve Zustand'ın Next.js rehberlerinde bu pattern özellikle önerilmektedir.

Next.js’te state management nedir ve kurumsal ölçekli uygulamalarda nasıl yapılandırılmalıdır?

Next.js’te state management yalnız browser global store yönetimi değildir. Server-owned state, URL state, local UI state, shared client state, workflow state ve server cache ayrı katmanlarda ele alınmalıdır. Kurumsal yapıda her state için source of truth, lifecycle, persistence ve request isolation tanımlanmalıdır. Redux Toolkit veya Zustand yalnız gerçekten shared browser state ihtiyacı olduğunda devreye girmelidir. Bu yaklaşım daha küçük client bundle, daha açık ownership ve daha güvenli data lifecycle sağlar.

Next.js projelerinde Redux Toolkit, Zustand ve TanStack Query arasından hangisi tercih edilmelidir?

Bu üç araç doğrudan aynı probleme çözüm değildir. Zustand shared browser-owned state, Redux Toolkit complex ve denetlenebilir client business state, TanStack Query ise asynchronous server cache için güçlüdür. Aynı kurumsal uygulamada üçü farklı alanlarda birlikte kullanılabilir. Seçimden önce state inventory çıkarmak gerekir. Tek library ile bütün state türlerini çözmeye çalışmak yerine responsibility separation daha sürdürülebilir olur.

Next.js App Router’da Server Components ve Client Components arasında state yönetimi nasıl yapılır?

Server Components server-owned data ve request context'i yönetir. Client Components interaction, browser API ve mutable UI state'i taşır. Server'dan client'a serializable initial props aktarılabilir. Client store gerekirse bu değerle initialize edilir ve hydration uyumu korunur. RSC global Redux veya Zustand store'a doğrudan bağlanmamalıdır.

Büyük ölçekli Next.js uygulamalarında global state, server state ve local state nasıl ayrılmalıdır?

Server state backend source of truth olarak Server Components veya query cache katmanında tutulmalıdır. Local state tek component içinde `useState` veya `useReducer` ile yaşamalıdır. Global client state yalnız birden fazla uzak component'ın gerçekten paylaştığı browser-owned mutable veri için kullanılmalıdır. URL state ayrı tutulmalıdır. Bu ayrım store boyutunu azaltırken cache ve hydration davranışını daha yönetilebilir hâle getirir.

Yakınımda Next.js state management ve kurumsal uygulama geliştirme eğitimi nerede bulabilirim?

Next.js state management ve frontend danışmanlığı yakınımda şeklinde araştırma yaparken yalnız kullanılan kütüphanelere değil, App Router, Server Components, request isolation, cache, TypeScript ve test yaklaşımına da bakmak faydalıdır. Kurumsal Next.js state management ve frontend mimarisi geliştirme hizmeti sunan bir ekibin gerçek proje örnekleri, kod standardı ve teknik karar süreçleri değerlendirilebilir. Diyarbakır Yazılım Topluluğu'nun çalışma alanları ve topluluk yaklaşımı hakkında https://www.diyarbakiryazilim.com.tr/about adresinden bilgi edinebilirsiniz. Proje örneklerini görmek için https://www.diyarbakiryazilim.com.tr/projects adresini inceleyebilirsiniz. Eğitim veya danışmanlık seçerken tek bir library eğitimi yerine state ownership ve kurumsal frontend mimarisi perspektifi sunulması uzun vadede daha fazla değer sağlar.

Sonuç: Next.js'te State Management Kütüphane Seçiminden Önce Ownership Kararıdır

Next.js'te State Management: Kurumsal Ölçekli Çözümler için en önemli sonuç, bütün state'i tek bir global store içine koymanın App Router'ın sunduğu server-first modeli gereksiz yere zayıflatabileceğidir. Server-owned veriyi Server Components ve server cache katmanında, navigation state'ini URL'de, local UI state'ini component'ta, shared browser state'i Zustand veya Redux Toolkit'te ve canlı server cache'i TanStack Query ya da uygun query katmanında tutmak daha açık bir mimari oluşturur. Request isolation, hydration, cache invalidation, persistence migration, güvenlik ve observability kütüphane seçiminin hemen yanında değerlendirilmelidir. Kurumsal projelerde bu ayrım doğru kurulduğunda state sistemi küçülür, client/server source of truth çatışmaları azalır ve ekiplerin yeni feature geliştirmesi daha öngörülebilir hâle gelir. Next.js, TypeScript ve kurumsal frontend mimarisi konusunda yaklaşımınızı değerlendirmek veya proje çalışmalarını incelemek için https://www.diyarbakiryazilim.com.tr, https://www.diyarbakiryazilim.com.tr/projects ve https://www.diyarbakiryazilim.com.tr/about adreslerini kullanabilirsiniz.

share
share:

İletişim

Birlikte inşa edelim

İşbirliklerine, ilginç sorunlara ve kod, tasarım ile diğer konular hakkında sohbetlere açığız.

bize ulaş→

Bizi başka yerlerde bulun

GitHub
@diyarbakir-yazilim
Twitter
@diyaryazilim
LinkedIn
diyarbakir-yazilim-toplulugu
Instagram
@diyarbakiryazilim
YouTube
@diyarbakiryazilim
Slack
diyarbakiryazilim
WhatsApp
Topluluğa Katıl
Email
info@diyarbakiryazilim.org
Sevgiyle ve kodla inşa ediliyor

© 2026 Diyarbakır Yazılım Topluluğu — Tüm hakları saklıdır.