Blog
Mert Özen'in yazılım geliştirme, backend, frontend ve DevOps üzerine blog yazıları.
React 18'den 19.3'e: Concurrent Rendering, Actions, use(), ref as prop, Activity, useEffectEvent, ViewTransition ve Fragment Ref'leri
React 18 concurrent rendering'in temelini (createRoot, batching, transition'lar), 19 Actions, use() ve ref'in props olmasını, 19.2 Activity ve useEffectEvent'i, 19.3 ise stable ViewTransition ve Fragment ref'lerini getirdi. Bookstore'a ViewTransition ve Fragment ref ekliyor, React Router 8.5'in deprecation'ını uyguluyor ve küçük bir React 18 projesini 18.3 uyarıları, TypeScript codemod'u ve elle düzeltmelerle 19.3'e yükseltiyoruz.
Next.js'e Kısa Bakış: Server Components, App Router, Server Action'lar, Cache Components ve Ne Zaman SPA Yeter?
Next.js, React'i sunucuda çalıştırır: Server Component'ler veriyi doğrudan await eder ve kodları tarayıcıya inmez, Cache Components ile neyin cache'leneceğini 'use cache' ve cacheLife ile sen seçersin, her Server Function ise doğrulama ve yetki kontrolü isteyen public bir endpoint'tir. Bookstore'un kitap detayını Next.js 16.4 ile Partial Prerender olarak sunuyor, curl ile Server Function'ı doğrudan çağırıyor ve SPA'nın ne zaman yettiğini tartışıyoruz.
Bookstore SPA'yı Uçtan Uca Bitirmek: Feature Klasörleri, Authentication, Environment'lar ve Deploy
Bir React SPA'yı production'a hazırlamak, feature sınırlarını lint kuralıyla korumak, VITE_ değişkenlerinin build sırasında bundle'a yazıldığını bilip secret'ı tarayıcıdan uzak tutmak ve oturumu token yerine HttpOnly cookie taşıyan bir BFF'e vermek demek. Bookstore'a ASP.NET Core ve YARP ile küçük bir BFF ekliyor, sign in akışını, SPA fallback'i, cache header'larını, nginx yapılandırmasını ve bundle analizini gerçek çıktılarla gösteriyoruz.
React'te Test: Vitest, React Testing Library ve MSW ile API Mock'lamak
React'i test etmenin pratik yolu, kodu kullanıcı gibi sorgulayan React Testing Library'yi Vite'la aynı config'i kullanan Vitest'le çalıştırmak ve API'yi kodu değiştirmeden network seviyesinde MSW ile taklit etmek. Bookstore'da saf applyChange fonksiyonunu, renderHook ile useDebouncedValue ve useCart'ı, user-event ile BookCard'ı ve memory router'daki gerçek route ağacıyla katalog ve checkout ekranlarını test ediyor; getBy/findBy farkını ve store sızmasını gerçek hata çıktılarıyla gösteriyoruz.
React'te Performans: Re-render'ı Anlamak, memo, useMemo, useCallback, React Compiler ve Profiler
Re-render'ı azaltmak ancak ölçülen bir maliyet varsa işe yarar ve çoğu zaman asıl maliyet React'in değil tarayıcının DOM işidir. Bookstore'un 5.000 satırlık stok sayfasında memo ve useCallback'in satır render'larını 5.000'den 1'e indirdiğini, inline callback'in bunu sildiğini, React Compiler'ın render süresini yarıya indirdiğini ama tıklamanın 400 ms'de kaldığını, virtualization'ın ise onu 40 ms'ye düşürdüğünü; ayrıca useDeferredValue ve Activity'nin etkisini ölçüyoruz.
React'te Global State: Context'in Sınırları, Zustand ve Ne Zaman Redux Toolkit?
Çoğu "global state" aslında server, URL ya da form state'idir; gerçekten global olan küçük client state için Zustand'ın selector'lı store'u Context'in her okuyanı render etme sorununu çözer, Redux Toolkit ise action log ve büyük ekip kuralları gerektiğinde gelir. Bookstore'da son bakılan kitapları ve sepet id'sini persist edilen bir store'a taşıyıp selector'sız okumanın 1 yerine 13 render ürettiğini ve yeni object döndüren selector'ın Zustand 5'te sonsuz döngüye girdiğini gösteriyoruz.
React'te Form'lar: Controlled Input, Form Action'ları, useActionState, useFormStatus ve react-hook-form + zod
Küçük formlar için React 19'un form action'ları (useActionState, useFormStatus, useOptimistic) yeterli; kalemli ve iç içe formlarda react-hook-form ile zod şeması daha az kod ve daha az render demek. Bookstore'un sipariş formunda controlled sürümün her tuşta render ettiğini, action'ın doğrulama hatasından sonra formu sıfırladığını, useOptimistic'in hata olunca kendiliğinden geri döndüğünü ve Problem Details hatalarının alanlara eşlenip odağın taşındığını gösteriyoruz.
React Router 8 ile Routing: Route'lar, Nested Layout, URL Parametreleri, Loader/Action ve Lazy Route
React Router 8'in data mode'unda route'lar createBrowserRouter'a object olarak verilir; layout route'u ve Outlet ile iç içe sayfalar, loader ile route'a girmeden önce veri, middleware ile guard, action ile form ve lazy ile code splitting elde edilir. Bookstore'u URL'lere bölüp aramayı query string'e taşıyor, aynı route'ta key'siz state'in sonraki kitaba taşındığını, lazy chunk'ın middleware yönlendirmesinden önce indiğini ve static sunucuda SPA fallback'in neden şart olduğunu gösteriyoruz.
React'te Veri Çekmek: fetch + Effect'ten TanStack Query'ye, Suspense ve use()
Effect ile veri çekmek cache, deduplication, retry ve invalidation vermez; TanStack Query bunları query key etrafında toplar. Bookstore kataloğunu ve sunucu tarafı sepeti TanStack Query'ye taşıyıp geri dönülen aramanın cache'ten geldiğini, optimistic update'in 500'de geri alındığını, 409 Problem Details'ın kullanıcıya gösterildiğini, Suspense'in 300 ms'lik gösterim aralığını ve render içinde oluşturulan promise'in use() ile üç saniyede 3.739 istek attığını ölçüyoruz.
useRef, Context ve Custom Hook'lar: DOM Erişimi, DI Yerine Context ve Hook Kuralları
useRef render tetiklemeyen bir kutudur (DOM node'u ya da timer id'si), Context ise bir değeri ağacın derinlerine props'suz taşır ve değişince onu okuyan her component'i render eder. Bookstore'da sepet, tema ve kullanıcıyı Context'e taşıyıp tema değişiminin 2 yerine 28 component render ettirdiği sürümü ölçüyor, inline ref callback'inin odak kaçırdığını, koşullu hook'un uygulamayı çökerttiğini ve aramayı custom hook'lara ayırmayı gösteriyoruz.
useEffect'i Doğru Kullanmak: Synchronization, Cleanup, Dependency Array ve "Effect'e İhtiyacın Olmayabilir"
useEffect bir lifecycle hook'u değil, component'i dış bir sistemle senkronize etme aracıdır: her setup'ın bir cleanup'ı olur, dependency array effect'in okuduğu reaktif değerlerin listesidir. Bookstore kataloğunu API aramasına bağlayıp debounce ve AbortController ile StrictMode'da bile tek istek gittiğini, cleanup'sız sürümde geciken yanıtın listeyi ezdiğini, effect ile türetilen sayının render'ı ikiye katladığını ve useEffectEvent'in gereksiz isteği önlediğini gösteriyoruz.
State'i Nerede Tutmalı? Lifting State Up, Controlled Input'lar, Türetilmiş State ve useReducer
State, ona ihtiyaç duyan component'lerin en yakın ortak atasında yaşamalı; hesaplanabilen değer state'e konmaz, kopya yerine kimlik saklanır, prop değişince sıfırlanacak state için key verilir. Bookstore kataloğunda sepeti App'e taşıyıp useReducer ve discriminated union ile tip güvenli bir reducer'a çeviriyor, ayrı tutulan toplamın silmede yanlış kaldığını, key'siz detay panelinin notu başka kitaba taşıdığını ve reducer'ın Node.js'te doğrudan çalıştığını gerçek çıktılarla gösteriyoruz.