
Karmaşık Form Yönetimi ve React Hook Form Entegrasyonu
Diyarbakır Yazılım
16.08.2026
#Yazılım#Teknoloji#Topluluk
React uygulamasında birkaç input içeren bir iletişim formunu yönetmek kolaydır, fakat gerçek kurumsal projelerde form yapısı kısa sürede çok daha büyük bir soruna dönüşebilir. On yıllık frontend geliştirme deneyimimde en zor bakım problemlerinden bazılarının yüzlerce satırlık tek form component'larından, dağınık validation kurallarından ve birbirini etkileyen state değişikliklerinden çıktığını gördüm. Karmaşık Form Yönetimi ve React Hook Form Entegrasyonu konusu bu nedenle yalnız `register` kullanmayı öğrenmekten ibaret değildir; form modeli, doğrulama, API sözleşmesi, erişilebilirlik, performans, autosave ve test yaklaşımı birlikte düşünülmelidir. React Hook Form doğru sınırlarla kullanıldığında özellikle dinamik, iç içe ve çok adımlı formların yönetimini önemli ölçüde sadeleştirebilir. Bu rehberde küçük bir formdan yüzlerce alan içeren kurumsal uygulamalara kadar ölçeklenebilen bir mimarinin nasıl kurulacağını adım adım ele alacağız.
Karmaşık Form Yönetimi Nedir?
Karmaşık form yönetimi yalnız çok sayıda input'u aynı ekranda göstermek anlamına gelmez. Form alanlarının birbirine bağlı olması, bazı değerlerin başka alanları görünür veya zorunlu hâle getirmesi, API'den gelen verinin düzenlenmesi ve kullanıcı değişikliklerinin kaybolmadan korunması form mimarisini zorlaştıran temel konulardır. Buna dinamik satırlar, nested object yapıları, server doğrulaması ve çok adımlı wizard eklendiğinde basit `useState` yaklaşımı hızla sınırlarına ulaşabilir. İyi bir form mimarisi state'in sahibini, validation'ın kaynağını ve API dönüşümünü açık biçimde ayırır. Böylece yeni alan eklemek eski davranışları beklenmedik biçimde bozan riskli bir işlem olmaktan çıkar.
Bir React Formunu “Karmaşık” Yapan Nedir?
Bir React formunu zorlaştıran asıl şey alan sayısından çok alanlar arasındaki ilişki ve yaşam döngüsüdür. On input içeren ancak bağımsız çalışan bir form, beş input içeren fakat birbirini sürekli değiştiren bir formdan daha kolay yönetilebilir. Kullanıcının bir seçimi başka alanları açıyor, API kontrolü çalıştırıyor veya farklı validation kuralları uyguluyorsa dependency sayısı artar. Edit modunda eski verilerin hydrate edilmesi ve submit sırasında API modeline dönüştürülmesi de ek sorumluluk getirir. Bu nedenle formun karmaşıklığını yalnız input adediyle değil veri modeli, transition sayısı ve dış sistem bağımlılıklarıyla ölçmek daha doğrudur.
Çok Sayıda Form Alanı
Form alanı sayısı arttıkça değer, hata, touched ve dirty bilgilerini manuel olarak takip etmek zorlaşır. Elli veya yüz alanın her biri için ayrı state setter yazmak component kodunu hızla büyütür ve aynı davranışın tekrar edilmesine neden olur. Alanları domain bazlı bölümlere ayırmak ve form state yönetimini React Hook Form gibi özel bir katmana bırakmak component sorumluluğunu azaltır. Büyük formlarda yalnız görünen alanların render edilmesi ve gerekli state'e subscription yapılması performans açısından da önemlidir. Alan sayısı büyüdükçe reusable field component ve schema tabanlı doğrulama bir tercih olmaktan çıkıp bakım kolaylığının temel araçlarından biri hâline gelir.
Dinamik Alanlar
Dinamik alanlar kullanıcı davranışına göre eklenen, silinen veya sırası değiştirilen form öğeleridir. Fatura kalemleri, adres listeleri, ekip üyeleri veya ürün varyantları bu yapının sık görülen örnekleridir. Her satırın kendi stable identity'si olmalı ve array index yalnız görsel sıra olarak değerlendirilmelidir. React Hook Form `useFieldArray` API'si bu tür listelerde alan ekleme, silme ve taşıma işlemlerini form state ile birlikte yönetmeye yardımcı olur. Dinamik yapı büyüdükçe satır component'larının ayrılması, schema validation ve server payload dönüşümü baştan planlanmalıdır.
İç İçe Veri Yapıları
Kurumsal formlar çoğu zaman düz key-value listesinden oluşmaz. Müşteri içinde adresler, adres içinde iletişim kişileri veya sipariş içinde ürünler ve her ürün içinde seçenekler bulunabilir. Böyle bir yapı nested field path ve nested error erişimini doğru yönetmeyi gerektirir. TypeScript `FieldPath` gibi tiplerle field name yazım hatalarının önemli bölümünü geliştirme sırasında yakalamaya yardımcı olabilir. İç içe veri yapısı API modeliyle birebir aynı olmak zorunda değildir; form için daha kullanışlı bir model tanımlanıp submit sırasında API payload'ına dönüştürülebilir.
Koşullu Alanlar
Koşullu alanlar başka bir değere göre görünür, zorunlu veya devre dışı hâle gelir. Örneğin şirket türü seçildiğinde vergi numarası alanı açılabilir veya teslimat seçimine göre farklı adres alanları gösterilebilir. Böyle alanlarda yalnız UI görünürlüğü değil validation davranışı ve gizlenen eski değerin form state'te kalıp kalmayacağı da belirlenmelidir. `useWatch`, `unregister` ve schema koşulları birlikte kullanılabilir. Dependency sayısı büyüdüğünde koşulları component içine dağınık `if` blokları olarak yazmak yerine domain kurallarını açık fonksiyon veya schema yapısında toplamak daha güvenilir olur.
Çok Adımlı Formlar
Çok adımlı form kullanıcıyı uzun bir veri giriş sürecinde küçük ve anlamlı aşamalardan geçirir. Onboarding, başvuru, checkout veya kurumsal kayıt süreçleri buna örnek olabilir. Her adımın kendi validation kapsamı bulunurken final submit bütün modelin yeniden doğrulanmasını gerektirebilir. Kullanıcı önceki adıma döndüğünde değerlerin korunması ve gerektiğinde draft olarak kaydedilmesi gerekir. Wizard state ile gerçek form state'i birbirinden ayrılırsa adım navigation logic'i input değerlerinin yönetimini gereksiz yere etkilemez.
Asenkron Doğrulama
Asenkron doğrulama bir alanın geçerli olup olmadığını öğrenmek için server veya dış servise ihtiyaç duyulduğunda devreye girer. Kullanıcı adı uygunluğu, e-posta benzersizliği, kupon kodu veya vergi numarası doğrulaması sık örneklerdir. Her input değişiminde kontrolsüz request göndermek hem kullanıcı deneyimini hem backend yükünü olumsuz etkileyebilir. Debounce, request cancellation ve son request'in sonucunu kabul etme gibi kurallar uygulanmalıdır. Asenkron client doğrulaması kullanıcıya erken feedback sağlasa da submit sırasında server aynı business kuralını yeniden kontrol etmelidir.
Geleneksel useState Yaklaşımı Neden Ölçeklenmez?
`useState` küçük ve yerel form state'i için son derece kullanışlıdır, fakat büyük formdaki bütün değerleri ayrı state olarak yönetmek tekrar miktarını artırır. Her input için value, change handler ve error davranışı yazıldığında component hızla form altyapısı koduyla dolar. Bir alan başka alanı etkilediğinde setter zincirleri ve effect'ler oluşabilir, bu da state'in hangi sırada neden değiştiğini takip etmeyi zorlaştırır. React Hook Form input registration ve form meta state yönetimini form odaklı bir abstraction altında toplar. Bu durum `useState` kullanımını yanlış yapmaz; yalnız form state ile normal UI state'in farklı problem alanları olduğunu gösterir.
Büyük Formlarda En Sık Karşılaşılan Problemler
Büyük formlarda karşılaşılan sorunlar genellikle birkaç ortak kaynaktan çıkar. Validation kuralları component, API adapter ve submit handler arasında tekrar edildiğinde farklı davranışlar oluşur. Formun tamamı her alan değişiminde yeniden render edildiğinde kullanıcı özellikle düşük güçlü cihazlarda gecikme hisseder. API'den gelen veri ile form modelinin birebir aynı kabul edilmesi create ve edit senaryolarını zorlaştırır. Ortak bir schema, açık state sınırları ve izole subscription modeli bu sorunların büyük bölümünü daha oluşmadan azaltır.
Validation Spaghetti
Validation spaghetti, doğrulama kurallarının component'lara, event handler'lara ve farklı helper dosyalarına dağılmasıdır. Aynı alanın required kuralı bir yerde, tarih karşılaştırması başka yerde ve API error mapping'i üçüncü yerde bulunursa davranışın tamamını görmek zorlaşır. Schema tabanlı yaklaşım mümkün olan kuralları tek yerde toplar. Server'a ait benzersizlik veya authorization gibi doğrulamalar ayrıca server katmanında kalır. Kuralların sahipliği net olduğunda yeni alan eklemek ve test yazmak daha kolay olur.
Gereksiz Re-render
Formun bütün değerlerini root component seviyesinde izlemek her input değişikliğinde geniş render alanı oluşturabilir. Özellikle yüzlerce dinamik satır veya ağır custom component bulunduğunda bu maliyet kullanıcı tarafından fark edilir hâle gelir. React Hook Form subscription odaklı API'lerle belirli field veya form state parçalarını izole takip etmeye izin verir. `useWatch` ve `useFormState` doğru scope'ta kullanıldığında yalnız ihtiyaç duyan component güncellenebilir. Performance optimizasyonu tahminle değil React Profiler üzerinden gerçek render davranışını ölçerek yapılmalıdır.
Karmaşık State Senkronizasyonu
Form state, local UI state, server data ve global store aynı değerleri ayrı ayrı tuttuğunda senkronizasyon problemleri oluşur. Örneğin API'den gelen müşteri adı React Query cache'te, form state'te ve global store'da aynı anda tutulursa hangisinin gerçek kaynak olduğu belirsizleşebilir. Form yalnız kullanıcı tarafından düzenlenen snapshot'ın sahibi olmalıdır. Server verisi query cache veya server katmanında, modal ve görünürlük gibi UI bilgileri component state'te kalmalıdır. Bu ayrım state değişikliklerinin yönünü ve reset davranışını çok daha anlaşılır yapar.
Tekrarlanan Kod
Her input için label, help text, error ve accessibility attribute'larını yeniden yazmak büyük projelerde ciddi tekrar oluşturur. Reusable field component bu yapıyı tek noktada standardize edebilir. Ancak aşırı generic bir `FormField` abstraction her UI kütüphanesini ve her field türünü tek API'ye zorlayarak tersine kullanım zorluğu yaratabilir. Temel pattern'leri paylaşmak, domain-specific component'ları ayrı bırakmak daha dengeli bir yaklaşımdır. Tekrar azaltma amacı component API'sini anlaşılmaz hâle getirmemelidir.
React Hook Form Nedir ve Neden Tercih Edilir?
React Hook Form, React ve React Native uygulamalarında form state yönetimi ve validation için geliştirilmiş açık kaynak bir kütüphanedir. Temel yaklaşımı native input'ların mevcut browser davranışından yararlanmak ve form state değişikliklerini mümkün olduğunca izole biçimde takip etmektir. `register`, `useController`, `useFieldArray`, `FormProvider` ve resolver entegrasyonları küçük formlardan büyük kurumsal yapılara kadar farklı ihtiyaçları kapsar. Kütüphanenin önemli avantajlarından biri form state ile UI state'i aynı global store'a koymayı gerektirmemesidir. Buna rağmen iyi mimari kendiliğinden oluşmaz; field ownership, schema ve API dönüşümü yine ekip tarafından doğru tasarlanmalıdır.
React Hook Form Nasıl Çalışır?
React Hook Form form alanlarını `register` veya controlled component durumunda `Controller` ve `useController` üzerinden form kontrolüne bağlar. Native input ref'lerinden ve subscription modelinden yararlanarak bütün formu her değişiklikte kontrollü component yaklaşımıyla yeniden render etmek zorunda kalmaz. Form state hata, dirty, touched ve submit bilgilerini ayrı meta state olarak yönetir. Resolver kullanıldığında Zod veya Yup gibi schema validator'lar submit veya belirlenen validation modunda devreye girebilir. Bu yapı form state'in component ağacında dağılmasını azaltırken kullanıcı arayüzü component'larının yine normal React prensipleriyle geliştirilmesine izin verir.
Controlled ve Uncontrolled Input Arasındaki Fark
Controlled input değerini React state üzerinden `value` prop ile alır ve her değişimde `onChange` üzerinden state günceller. Uncontrolled input ise mevcut değerini DOM üzerinde tutar ve React gerektiğinde ref veya form API üzerinden bu değere ulaşır. React Hook Form native input'larda uncontrolled yaklaşımın avantajlarından güçlü biçimde yararlanır. Material UI gibi controlled API kullanan component'larda `Controller` veya `useController` devreye girer. Bir yaklaşım diğerinden mutlak biçimde üstün değildir; input component'ın API'sine ve uygulamanın davranış ihtiyacına göre uygun entegrasyon seçilmelidir.
React Hook Form'un Performans Yaklaşımı
React Hook Form'un performans yaklaşımı gereksiz component render'larını azaltmaya ve form state subscription'larını ihtiyaç duyulan alana yaklaştırmaya dayanır. Root component'ta bütün form değerlerini `watch()` ile dinlemek bu avantajın önemli bölümünü ortadan kaldırabilir. Field bazlı `useWatch`, form meta state için `useFormState` ve kontrollü component'larda `useController` daha dar subscription sağlayabilir. Native input registration ek React state katmanı gerektirmeden değer toplamayı kolaylaştırır. Büyük formlarda library seçiminin yanında component sınırları ve render edilen satır sayısı da performansı belirleyen önemli faktörlerdir.
React Hook Form Hangi Projelerde Kullanılmalı?
Birden fazla validation kuralı, edit formu, dynamic field array veya reusable field component bulunan React projelerinde React Hook Form güçlü adaydır. Kurumsal CRUD ekranları, onboarding wizard'ları, teklif formları ve konfigürasyon panelleri kütüphanenin faydasını kolayca gösterir. TypeScript ve schema resolver kullanımı büyük codebase'de field name ve payload hatalarını azaltmaya yardımcı olur. UI kütüphaneleriyle entegrasyon ihtiyacı Controller üzerinden yönetilebilir. Kütüphaneyi yalnız popüler olduğu için değil, form state yönetiminde gerçek tekrar ve performans problemi çözdüğü için seçmek gerekir.
React Hook Form Hangi Durumlarda Gereksiz Olabilir?
Tek input ve tek submit button içeren küçük formda özel form library kullanmak gerekmeyebilir. Native HTML validation ve basit React state çoğu durumda yeterlidir. Server Component ve Server Action merkezli çok basit Next.js formunda da browser `FormData` yaklaşımı yeterli olabilir. Kütüphane eklemek dependency, öğrenme ve update sorumluluğu oluşturur. Form büyüme ihtimali bulunmuyorsa en sade çözümü kullanmak uzun vadede daha düşük bakım maliyeti sağlayabilir.
React Hook Form Kurulumu ve Temel Entegrasyon
React Hook Form entegrasyonunda ilk adım yalnız paketi kurmak değil form modelini ve default değerleri doğru tanımlamaktır. `useForm` formun merkezi kontrol nesnesini oluşturur ve register, submit, reset ve state API'lerini sağlar. TypeScript kullanıldığında form modeli generic parametre olarak verilerek field path güvenliği güçlendirilebilir. Schema validator kullanılacaksa resolver paketi ve ilgili validator ayrıca eklenir. Temel kurulum ne kadar açık tutulursa büyük formun diğer bölümlere ayrılması da o kadar kolay olur.
React Hook Form Kurulumu
React Hook Form npm, pnpm, Yarn veya benzeri paket yöneticisiyle projeye eklenebilir. Validation schema kullanılacaksa `@hookform/resolvers` ve Zod veya Yup gibi seçilen validator ayrıca kurulur. Package version'ları lockfile içinde sabitlenmeli ve özellikle major güncellemelerde migration notları incelenmelidir. Kurulumdan sonra ilk form küçük bir örnekle `useForm`, `register` ve `handleSubmit` kullanılarak doğrulanabilir. Büyük projede ortak form helper ve field component'lar ilk günden kurulabilir, ancak gerçek ihtiyaç görülmeden aşırı abstraction oluşturulmamalıdır.
useForm Yapısı
`useForm` React Hook Form kullanımının merkezindeki hook'tur. Default values, validation mode, resolver ve unregister davranışı gibi temel seçenekler burada tanımlanabilir. Hook'un döndürdüğü method'lar form lifecycle'ın farklı bölümlerini yönetir. Büyük projede bütün method'ları her component'a prop olarak geçirmek yerine FormProvider veya yalnız gerekli method'u iletmek daha okunabilir olabilir. `useForm` configuration değerlerinin neden seçildiği ortak form standardında açıkça belgelenmelidir.
register
`register` native veya ref destekleyen input'u form kontrolüne bağlar. Field name, validation rule ve value transformation seçenekleri aynı kayıt sırasında verilebilir. TypeScript form modeli tanımlandığında name değeri geçerli field path'lerle sınırlandırılabilir. Custom controlled UI component `register` sözleşmesine uymuyorsa Controller tercih edilmelidir. Her input için otomatik Controller kullanmak yerine önce register ile doğrudan entegrasyon mümkün mü kontrol etmek performans ve kod sadeliği açısından faydalıdır.
handleSubmit
`handleSubmit` browser submit olayını form validation ve data extraction süreciyle birleştirir. Geçerli değerlerde success callback, validation başarısız olduğunda error callback çalıştırılabilir. Submit handler API çağrısını doğrudan yapabilir veya ayrı application service'e delegasyon verebilir. Handler içinde UI, payload transformation ve network logic'in tamamını toplamak büyüdükçe okunabilirliği azaltır. `toApiPayload` benzeri dönüşüm ve mutation fonksiyonlarını ayrı tutmak test edilebilirliği artırır.
formState
`formState` error, dirty, touched, submit ve validity gibi form meta bilgilerini içerir. Component yalnız ihtiyaç duyduğu parçaya erişmelidir. Formun her köşesinde bütün formState object'ini kullanmak geniş subscription davranışı oluşturabilir. Büyük formda belirli subtree için `useFormState` ile dar scope tercih edilebilir. `isDirty`, `dirtyFields` ve `isSubmitting` gibi değerler autosave, unsaved warning ve submit button davranışında sık kullanılır.
control
`control` React Hook Form'un internal form kontrolünü Controller, useController, useFieldArray ve useWatch gibi hook'lara iletmek için kullanılır. Native register kullanılan basit input'ların control prop alması gerekmez. Büyük formda control prop drilling oluşuyorsa FormProvider ve context kullanılabilir. Control nesnesini global application state olarak saklamak doğru değildir. Form instance'ın kendi lifecycle'ı içinde kalması reset ve unmount davranışını daha güvenli tutar.
getValues
`getValues` mevcut form değerlerini subscription oluşturmadan okumak için kullanılabilir. Bu özellik submit dışındaki hesaplama veya imperative kontrol senaryolarında faydalıdır. UI'nın sürekli bu değere göre yeniden render olması gerekiyorsa `getValues` yerine `useWatch` daha doğru olabilir. Method'u her render'da koşullu görünürlük için çağırmak reactive davranışı garanti etmez. Kullanım amacı anlık snapshot okumak olduğunda oldukça kullanışlıdır.
setValue
`setValue` belirli field değerini programatik olarak değiştirmeyi sağlar. API seçimine göre bağlı alanı doldurma veya kullanıcı aksiyonuyla hesaplanan bir değeri güncelleme gibi durumlarda kullanılabilir. Dirty, touched ve validation davranışının tetiklenip tetiklenmeyeceği seçeneklerle yönetilebilir. Çok sayıda `setValue` çağrısı form dependency logic'inin dağınık olduğuna işaret edebilir. Hesaplanabilir değerleri state'e yazmak yerine render sırasında türetmek bazı senaryolarda daha sade olabilir.
reset
`reset` formu yeni default değerlerle veya başlangıç durumuyla yeniden kurmak için kullanılır. Edit formunda API verisi geldikten sonra hydrate işlemi için yaygın yöntemdir. Reset sırasında dirty veya touched state'in korunup korunmayacağı kullanım senaryosuna göre seçilebilir. Kullanıcı düzenleme yapmışken arka plandan yeni server data geldiğinde otomatik reset yapmak veri kaybına yol açabilir. Server data refresh ile user draft arasındaki conflict davranışı açıkça tasarlanmalıdır.
TypeScript ile Form Veri Tiplerinin Tanımlanması
TypeScript büyük form modellerinde field name, nested path ve submit payload hatalarını geliştirme aşamasında yakalamaya yardımcı olur. `useForm()` biçimindeki generic kullanım form method'larını aynı model üzerinden type-safe hâle getirir. Schema tabanlı validation kullanıldığında form type schema'dan türetilebilir ve tekrar eden type tanımı azaltılabilir. API modeliyle form modeli her zaman aynı olmamalıdır, çünkü UI tarih, seçim veya geçici alanları farklı biçimde tutabilir. TypeScript'in en büyük faydası yalnız autocomplete değil refactoring sırasında değişen field contract'larını codebase boyunca görünür hâle getirmesidir.
FieldValues
`FieldValues`, React Hook Form type sisteminde form veri modellerinin temel constraint türlerinden biridir. Generic reusable component yazarken belirli bir form shape yerine farklı form modellerini kabul etmek için kullanılabilir. Fazla geniş generic kullanmak type inference'ı zayıflatabileceği için yalnız reusable altyapı katmanında ihtiyaç olduğunda tercih edilmelidir. Uygulama feature'larında mümkün olduğunca gerçek domain form type'ı kullanılmalıdır. Böylece field value ve validation output hakkında daha güçlü compile-time kontrol elde edilir.
FieldPath
`FieldPath` belirli form modelindeki geçerli field name yollarını type olarak ifade eder. Nested object ve array yapısında yanlış string path yazılmasını azaltır. Reusable field component `name` prop'unu `FieldPath` olarak tanımlayabilir. Bu yaklaşım özellikle büyük form refactoring'lerinde eski field isimlerinin kolay fark edilmesini sağlar. Runtime data yine doğrulanmalıdır, çünkü TypeScript kullanıcıdan veya API'den gelen gerçek değerin güvenli olduğunu tek başına garanti etmez.
Type-safe Field Names
Type-safe field name yaklaşımı `"customer.addres.city"` gibi yazım hatalarının compile aşamasında yakalanmasına yardımcı olur. Form component'ları string isimleri serbestçe kabul etmek yerine form modeline bağlı generic contract kullanabilir. Dynamic field array'lerde index içeren path'lerin oluşturulması dikkat gerektirir. TypeScript literal type ve FieldPath kullanımı mümkün olduğunda refactoring güvenliğini artırır. Field name helper'larını aşırı soyutlamak yerine readable ve IDE tarafından anlaşılabilir yapı tercih edilmelidir.
Karmaşık Formlar İçin Doğru Mimari Nasıl Kurulur?
Karmaşık form mimarisinde en önemli karar, formu tek component yerine sorumluluk katmanlarına ayırmaktır. Schema validation kurallarını, form state kullanıcı taslağını, UI component'ları görünümü ve API adapter dış sistem sözleşmesini yönetebilir. Formun farklı bölümleri domain bazlı component'lara ayrıldığında code ownership daha anlaşılır olur. UI state ile form değerlerinin birbirine karışmaması reset ve test davranışını kolaylaştırır. Mimari, form kütüphanesinin API'sini uygulamanın her yerine yaymak yerine domain ihtiyacını merkezde tutmalıdır.
Schema → State → UI → API Katmanları
Schema katmanı form değerlerinin yapısını ve mümkün olan doğrulama kurallarını tanımlar. State katmanı kullanıcı tarafından düzenlenen geçici değerleri ve form meta bilgisini yönetir. UI katmanı input, label, error ve interaction davranışını render eder. API katmanı form modelini backend payload'ına dönüştürür ve server hatalarını tekrar form modeline eşler. Bu dört katmanın ayrılması create, edit, autosave ve test senaryolarının aynı temel yapıyı tekrar kullanmasını kolaylaştırır.
Formu Domain Bazlı Bölümlere Ayırma
Büyük bir kullanıcı formu `PersonalInfoSection`, `AddressSection` ve `PermissionsSection` gibi business anlam taşıyan bölümlere ayrılabilir. Bu ayrım yalnız dosya boyutunu küçültmez, ekiplerin belirli domain bölümlerini bağımsız geliştirmesine yardımcı olur. Her bölüm FormProvider üzerinden ortak form instance'a erişebilir. Section component yalnız kendi field'larını ve validation mesajlarını bilmelidir. Böylece parent form submit ve API orchestration'a odaklanırken child component'lar input detaylarını yönetir.
Form State ile UI State'i Ayırma
Form state submit edilecek business değerleri taşırken UI state kullanıcı arayüzünün geçici görünümünü yönetir. Örneğin seçilen müşteri form değeridir, müşteri seçim modalının açık olup olmadığı UI state'tir. Modal state'i React Hook Form içine koymak submit payload'ını gereksiz UI ayrıntılarıyla kirletir. Tersine gerçek form değerini local component state'te tutup submit öncesi form state'e kopyalamak ikinci source of truth oluşturabilir. Her state parçası için “bu değer API payload'ının veya form taslağının parçası mı?” sorusu iyi bir karar filtresidir.
React Hook Form İçinde Tutulması Gereken State
Kullanıcının submit edeceği input değerleri, form validation error'ları ve dirty bilgisi React Hook Form içinde tutulmalıdır. Dinamik satırlar ve nested form object'leri de aynı form instance'ın parçası olabilir. Submit payload'ına girmeyen modal visibility veya dropdown panel open state burada saklanmamalıdır. Server'dan gelen reference listeler form state değil query data olarak kalmalıdır. Form state ne kadar business draft'a odaklanırsa reset, autosave ve submission davranışı o kadar açık hâle gelir.
Local Component State'te Tutulması Gereken State
Accordion açık mı, modal görünür mü veya belirli helper panel genişletildi mi gibi state'ler local component'a aittir. Bu bilgilerin form submit sonucuyla ilgisi yoktur. Local state kullanmak form schema'yı UI detaylarından korur. Component unmount olduğunda doğal reset davranışı sağlanır. Bir UI state çok sayıda uzak component tarafından paylaşılmaya başlarsa ayrıca Context veya client store değerlendirilebilir.
Server State Olarak Tutulması Gereken Veri
Ülke listesi, kullanıcı seçenekleri, ürün kataloğu veya backend'de yaşayan mevcut kayıt server state'tir. Bu data React Query, Server Component veya başka data fetching katmanında tutulabilir. Form mevcut kaydın düzenlenebilir snapshot'ını alır, fakat server cache'in kendisini sahiplenmez. Reference data değiştiğinde query layer bunu güncelleyebilir. Server data ile form draft ayrımı özellikle uzun edit oturumlarında conflict yönetimini daha görünür hâle getirir.
Fetch → Logic → View Yaklaşımı
Fetch katmanı API veya query kaynaklarından gerekli verileri toplar. Logic katmanı bu veriyi form modeline dönüştürür, permission ve mode gibi kararları üretir. View katmanı React Hook Form context'inden gelen değerleri kullanarak ekranı render eder. Bu ayrım test sırasında network ve UI davranışının birbirinden bağımsız doğrulanmasını sağlar. Her projede birebir üç ayrı dosya zorunlu değildir, ancak sorumlulukların zihinsel olarak ayrılması büyük form component'larını sadeleştirir.
Tek Bir Dev Form Component'inden Kaçınmak
Bin satırlık tek form component başlangıçta hızlı geliştiriliyor gibi görünebilir, fakat birkaç ekip aynı dosyada çalışmaya başladığında değişiklik riski büyür. Validation, API mapping ve UI conditional logic aynı yerde toplanır. Domain section'lara bölmek code review alanını küçültür ve reusable pattern oluşmasını sağlar. Parent form yalnız orchestration, submit ve genel error state'i yönetebilir. Component bölmek yalnız satır sayısını azaltmak için değil ownership ve render scope belirlemek için yapılmalıdır.
Schema Tabanlı Form Doğrulama
Schema tabanlı doğrulama form modelinin geçerli kabul edilme kurallarını merkezi biçimde tanımlamaya yardımcı olur. Zod ve Yup gibi araçlar React Hook Form resolver entegrasyonlarıyla kullanılabilir. Required, format ve cross-field kontrollerinin önemli bölümü schema içinde ifade edilebilir. Server'ın gerçek business validation'ı yine ayrıca çalışmalıdır, çünkü client kodu kullanıcı tarafından atlanabilir. Schema'nın form modeliyle aynı kaynaktan type üretebilmesi TypeScript kullanan büyük projelerde tekrar miktarını azaltır.
Field-Level Validation
Field-level validation belirli input'un kuralını doğrudan `register` seçeneklerinde tanımlamayı sağlar. Basit required, minLength veya pattern kontrolünde ek schema dependency gerekmeyebilir. Küçük formda bu yaklaşım son derece okunabilir olabilir. Kurallar cross-field veya nested yapıya dönüştüğünde component içine dağılan validation yönetimi zorlaşır. Bu noktada schema tabanlı yaklaşım kuralları tek modelde toplamak için daha uygun hâle gelir.
Schema-Based Validation
Schema-based validation bütün form veya belirli domain object için ortak doğrulama modeli oluşturur. Field kuralları, nested object ve array kontrolleri aynı yapı içinde görülebilir. Resolver schema sonucunu React Hook Form error modeline bağlar. Aynı schema server tarafında tekrar kullanılabiliyorsa client ve server rule drift riski azalabilir. Buna rağmen database uniqueness veya authorization gibi backend'e bağımlı kurallar yalnız client schema'ya bırakılmamalıdır.
Zod ile React Hook Form Entegrasyonu
Zod TypeScript-first schema validation yaklaşımıyla nested form modellerinde güçlü type inference sağlar. `@hookform/resolvers` içindeki Zod resolver schema sonucunu React Hook Form validation akışına bağlayabilir. Zod 4 güncel kararlı sürüm olarak TypeScript ve modern browser ortamlarında kullanılabilir. Schema'dan output type türetmek form type ile validation modelinin ayrı ayrı yazılmasını azaltır. Transform ve coercion kullanıldığında input type ile output type arasındaki fark açıkça yönetilmelidir.
zodResolver
`zodResolver` Zod schema'yı React Hook Form resolver contract'ına uyarlayan entegrasyon katmanıdır. `useForm` configuration içinde resolver olarak verildiğinde field ve form-level schema hataları form state'e aktarılır. Resolver'ın async mode davranışı dış validation ihtiyacına göre değerlendirilebilir. Error message'lar kullanıcı diline ve product terminolojisine uygun yazılmalıdır. Validation schema'yı UI component içine gömmek yerine domain veya feature seviyesinde tutmak tekrar kullanım ve test açısından daha iyidir.
Schema'dan TypeScript Type Üretmek
Zod schema'dan TypeScript type türetildiğinde aynı form modelini iki farklı yerde manuel tanımlamak gerekmez. `z.infer` veya input/output type yardımcıları schema dönüşüm davranışına göre kullanılabilir. Coercion veya transform varsa kullanıcının girdiği değer ile validation sonrası değer aynı type olmayabilir. API payload type ayrıca farklı olabilir ve bu durum adapter ile açıkça gösterilmelidir. Type üretmek compile-time tekrarını azaltır, runtime server response'unun yine schema ile doğrulanması gerekebilir.
Yup ile React Hook Form Entegrasyonu
Yup uzun süredir JavaScript form doğrulamasında kullanılan olgun bir schema kütüphanesidir. React Hook Form resolver projesi Yup entegrasyonunu doğrudan destekler. Mevcut codebase Yup schema'larına sahipse sırf yeni proje trendi için hepsini Zod'a taşımak gerekli olmayabilir. Conditional validation API'si birçok legacy ve kurumsal formda yeterli esneklik sunar. Yeni seçimde TypeScript inference, ekip deneyimi ve mevcut schema yatırımı birlikte değerlendirilmelidir.
Zod mu Yup mı?
Zod TypeScript-first yaklaşımı ve schema'dan güçlü type inference nedeniyle yeni TypeScript projelerinde sık tercih edilir. Yup daha eski ve geniş kullanım geçmişine sahiptir, mevcut projelerde önemli schema yatırımı bulunabilir. İki araç da React Hook Form resolver ile kullanılabilir. Karar syntax tercihinden önce migration maliyeti, ekip bilgisi ve server validation reuse ihtiyacına göre verilmelidir. Büyük codebase'de tek validator standardı belirlemek farklı feature'ların farklı error davranışı üretmesini azaltabilir.
Cross-Field Validation
Cross-field validation bir alanın geçerliliğinin başka alanın değerine bağlı olduğu durumları kapsar. Şifre tekrarı, tarih aralığı ve minimum maksimum değer ilişkileri sık örneklerdir. Bu kurallar field-level callback'lere dağıtıldığında dependency yönünü takip etmek zorlaşabilir. Schema seviyesinde object validation bütün ilgili değerleri birlikte görür. Error'ın hangi field üzerinde gösterileceği kullanıcı deneyimine göre açıkça belirlenmelidir.
Şifre ve Şifre Tekrarı
Şifre ve tekrar alanı ayrı ayrı format kontrolünden geçse bile birbirine eşit olmalıdır. Cross-field schema kuralı iki değeri birlikte karşılaştırabilir. Hata genellikle tekrar alanına bağlanarak kullanıcıya düzeltmesi gereken yer açık gösterilir. Şifre policy'si yalnız client'ta uygulanmamalı ve backend aynı minimum gereksinimleri doğrulamalıdır. Şifre değeri log, analytics veya browser persistence içine yazılmamalıdır.
Başlangıç ve Bitiş Tarihi
Bitiş tarihi başlangıç tarihinden önce olamaz gibi kurallar iki field'ın ilişkisini kontrol eder. Date picker component değerinin string, Date veya başka formata dönüştürülmesi form modelinde netleştirilmelidir. Timezone farkı backend ve frontend arasında sürpriz sonuç oluşturabilir. Cross-field schema kullanıcıya doğru field üzerinde anlamlı hata döndürmelidir. Tarih validation yalnız UI picker min/max değerine güvenmemeli ve server tarafından da tekrar doğrulanmalıdır.
Conditional Validation
Conditional validation bir field'ın zorunluluk veya format kuralını başka değere göre değiştirir. Örneğin fatura türü şirket ise vergi numarası required olabilir. UI field'ı gizlerken schema da aynı koşulu bilmelidir. Gizlenen eski değer payload'a gönderilmeyecekse unregister veya payload dönüşümünde temizleme yapılabilir. Koşullar arttıkça schema ve UI'nın aynı domain helper üzerinden karar üretmesi drift riskini azaltır.
Cross-Row Validation
Field array içinde her satır tek başına geçerli olsa bile satırların birlikte uyması gereken kurallar olabilir. Aynı ürün kodunun iki kez eklenmemesi veya toplam dağılımın yüzde yüz olması buna örnektir. Bu kontroller row-level validation yerine array schema seviyesinde yapılabilir. Hatanın belirli satıra mı yoksa bütün tabloya mı ait olduğu UI'da açıkça gösterilmelidir. Büyük array'de pahalı cross-row hesaplamalar her keystroke'ta çalıştırılmadan uygun validation timing seçilebilir.
Duplicate Satır Kontrolü
Duplicate kontrolünde belirli unique key değerleri array boyunca karşılaştırılır. Aynı ürün, e-posta veya kod birden fazla satırda yer alamıyorsa schema set tabanlı kontrol yapabilir. Hata yalnız genel mesaj olarak verilirse kullanıcı hangi satırı düzeltmesi gerektiğini bulmakta zorlanabilir. Duplicate index'ler hesaplanıp ilgili row error'larına map edilebilir. Server da database veya business rule seviyesinde duplicate kontrolünü tekrar uygulamalıdır.
Toplam ve Limit Kontrolü
Bütçe dağılımı veya yüzde alanlarında satırların toplamı belirli limite uymalı olabilir. Bu değer derived olduğu için ayrıca form state'e yazmak yerine validation sırasında hesaplanabilir. Kullanıcıya mevcut toplam ve kalan miktar gerçek zamanlı gösterilebilir. Büyük array'de hesaplama memoization veya dar `useWatch` subscription ile optimize edilebilir. Submit sırasında server aynı toplamı authoritative biçimde tekrar hesaplamalıdır.
React Hook Form ile Dinamik Form Alanları
Dinamik form alanları React Hook Form'un `useFieldArray` API'sinin en güçlü kullanım alanlarından biridir. Array içindeki her satır form state'in bir parçası olur ve ekleme, silme veya sıralama işlemleri özel method'larla yönetilir. Stable `field.id` değeri React key olarak kullanıldığında component identity daha güvenli korunur. Array validation satır sayısı ve cross-row business rule'ları içerebilir. Çok sayıda satır bulunan formda row component izolasyonu ve gerektiğinde virtualization düşünülmelidir.
Dinamik Form Nedir?
Dinamik form kullanıcı aksiyonu veya data modeline göre field sayısı değişebilen formdur. Kullanıcı yeni telefon numarası, adres, ürün satırı veya ekip üyesi ekleyebilir. Her yeni satırın başlangıç değeri ve validation kuralı bulunmalıdır. Silinen satırın form state'te kalıp kalmayacağı submission davranışını etkiler. Dinamik form tasarımında UI interaction kadar API payload'ın array değişikliklerini nasıl işleyeceği de düşünülmelidir.
useFieldArray Nasıl Çalışır?
`useFieldArray`, form içindeki belirli array path'ini yönetmek için `control` ve `name` bilgisiyle çalışır. Hook `fields` listesinin yanında append, prepend, insert, remove, move, swap, update ve replace gibi method'lar sağlar. Her field React render identity için benzersiz bir id içerir. Mutation method'ları array state'i React Hook Form internal control ile senkron biçimde günceller. Çok sayıda operasyonu arka arkaya çağırmak yerine kullanıcı aksiyonunu tek ve açık transition olarak tasarlamak daha öngörülebilir sonuç verir.
fields
`fields`, render edilmesi gereken array satırlarının mevcut yapısını temsil eder. Her öğe form değerlerine ek olarak stable key amacıyla üretilen `id` değerini içerir. Gerçek güncel input value okumak gerektiğinde fields listesini tek source olarak kabul etmek yerine form state API'leri kullanılmalıdır. Fields daha çok row structure ve default data için render referansı sağlar. Component'lar yalnız kendi index alanlarını register ederek büyük array'i daha küçük render sınırlarına bölebilir.
append
`append` array'in sonuna yeni bir satır ekler. Eklenen object mümkün olduğunca form modelindeki gerekli default alanları içermelidir. Eksik partial object ileride uncontrolled veya validation davranışını zorlaştırabilir. Kullanıcı satır ekledikten sonra yeni field'a focus verilmesi UX'i iyileştirebilir. Business limit varsa append öncesi veya array validation seviyesinde maksimum satır sayısı kontrol edilmelidir.
prepend
`prepend` yeni satırı array'in başına ekler. Bütün mevcut index'ler değişeceği için React key olarak index kullanılması bu senaryoda özellikle sorun yaratır. Stable `field.id` component identity'yi korumaya yardımcı olur. İlk satırın business açısından özel anlamı varsa prepend davranışı buna göre sınırlandırılmalıdır. Çok büyük array'de kullanıcı gerçekten başa ekleme ihtiyacı duyuyor mu UX açısından ayrıca değerlendirilmelidir.
insert
`insert` belirli index'e yeni field object ekler. Kullanıcı satırlar arasında yeni kayıt oluşturacaksa faydalıdır. Default değerler eksiksiz verilmelidir. Insert sonrası index'ler değişse bile stable id key kullanımı row component state'in yanlış satıra taşınma riskini azaltır. API satırların sırasını saklıyorsa order bilgisinin backend payload'ında nasıl ifade edildiği açık olmalıdır.
remove
`remove` belirli index'teki veya seçilen satırları array'den çıkarır. Edit formunda bu işlem her zaman database kaydını hemen silmek anlamına gelmeyebilir. Bazı uygulamalarda silinen persisted row id'leri ayrı delete listesine eklenip submit sırasında backend'e gönderilir. Kullanıcı yanlışlıkla satır silebiliyorsa undo veya confirmation değerlendirilebilir. Minimum row sayısı varsa remove action UI ve schema tarafından birlikte korunmalıdır.
move
`move` bir field array öğesini başka index'e taşır. Drag-and-drop sıralama gibi deneyimlerde sık kullanılır. Stable id sayesinde React aynı row component'ını farklı sırada koruyabilir. Sıralama business data'nın parçasıysa backend'e açık order değeri gönderilmelidir. Her drag hareketinde autosave request göndermek yerine işlem sonu debounce veya explicit save tercih edilebilir.
swap
`swap` iki satırın yerini değiştirir. Move'dan farklı olarak iki index doğrudan birbirleriyle takas edilir. Ranking veya priority listelerinde kullanıcıya basit yukarı aşağı control sunarken kullanılabilir. Row component key'leri yine `field.id` üzerinden kurulmalıdır. Sıra değişimi validation sonucunu etkiliyorsa array-level doğrulama yeniden çalıştırılabilir.
update
`update` belirli index'teki field array object'ini yeni değerle değiştirir. Bu işlem ilgili row'un yeniden mount davranışına yol açabileceği için yalnız tek field değeri değiştirmek gerektiğinde `setValue` daha uygun olabilir. Update bütün row modelinin yenilenmesi için kullanışlıdır. API'den gelen bir preset seçimi satırın bütün alanlarını değiştirecekse anlamlı kullanım alanıdır. Hangi method'un hangi render etkisini oluşturduğu büyük row component'larda performans testleriyle doğrulanmalıdır.
replace
`replace` array'in tamamını yeni listeyle değiştirir. Import edilen veri, template seçimi veya server'dan tamamen yenilenen array bu method için uygun olabilir. Kullanıcının dirty değişiklikleri varsa replace öncesinde kayıp riski değerlendirilmelidir. Yeni listede gerekli default field'lar ve id olmayan business değerleri doğru hazırlanmalıdır. Büyük liste replacement'ı ciddi render maliyeti oluşturabileceği için gerekli durumda row virtualization ve batch UX düşünülmelidir.
Neden field.id Key Olarak Kullanılmalı?
React list render ederken key değerini component identity'yi korumak için kullanır. Array index key olduğunda bir satır silindiğinde sonraki satırlar farklı veriyi aynı component identity ile almaya başlayabilir. Input state ve focus gibi davranışlarda bu durum beklenmedik sonuçlar üretebilir. `useFieldArray` her field için benzersiz `id` ürettiği için `key={field.id}` kullanımı önerilen modeldir. Index field path için gerekli olabilir, ancak React key ile aynı sorumluluğu taşımamalıdır.
Dinamik Alanlara Default Value Atamak
Yeni eklenen satır mümkün olduğunca tam bir default object ile oluşturulmalıdır. Text field için boş string, checkbox için false veya nested object için uygun başlangıç yapısı tanımlanabilir. Undefined ve kontrollü UI component kombinasyonları warning ve görünürlük sorunlarına yol açabilir. Form schema ile default value shape aynı model üzerinde anlaşmalıdır. Default value factory kullanmak her append işleminde tekrar object yazılmasını azaltabilir.
Field Array Validation
Field array validation hem her row içindeki alanları hem array'in bütünü için business kurallarını kapsar. Minimum row sayısı, maksimum row sayısı veya duplicate kontrolü array-level schema içinde ifade edilebilir. Satır içindeki required ve format kuralları row schema'ya aittir. Error UI genel array mesajı ile row-specific mesajları birbirinden ayırmalıdır. Büyük listelerde bütün schema'nın her tuş vuruşunda çalıştırılması pahalıysa validation mode yeniden değerlendirilebilir.
Minimum ve Maksimum Satır Sayısı
Bir teklif formunda en az bir ürün veya en fazla belirli sayıda adres bulunması gerekebilir. `useFieldArray` rules veya schema validation bu limitleri ifade edebilir. UI minimuma ulaşıldığında remove butonunu devre dışı bırakabilir. Maksimuma ulaşıldığında append action gizlenebilir veya açıklayıcı mesaj gösterilebilir. Server aynı limitleri tekrar doğrulamalıdır, çünkü client UI kuralı doğrudan request gönderilerek aşılabilir.
Nested useFieldArray ile İç İçe Form Yapıları
Nested field array, array içindeki bir item'ın kendisinin başka array veya nested object taşıdığı yapılardır. Sipariş içindeki ürün ve ürün içindeki varyantlar buna örnek olabilir. Bu modelde field name, validation error ve component ownership daha dikkatli tasarlanmalıdır. Her nested array kendi `useFieldArray` hook'unu ilgili path ile kullanabilir. Derin yapı büyüdükçe API modeliyle form modeli arasına dönüşüm katmanı koymak codebase'i daha anlaşılır tutar.
Array İçinde Object Yönetimi
Field array öğeleri çoğu zaman primitive yerine object'tir. Her object birkaç input ve nested field içerebilir. Row component index ve control üzerinden kendi field path'lerini oluşturur. TypeScript array path'lerinin doğru olduğundan emin olmak için generic type'lar kullanılabilir. Object şekli çok büyükse satır component'ını domain alt bölümlerine ayırmak render ve code ownership açısından fayda sağlar.
Array İçinde Array Yönetimi
Bir array öğesinin içinde başka array varsa her inner list için ayrı `useFieldArray` kullanılabilir. Parent index inner array name'in bir parçası olur. Index değişimi path'i etkilediği için React key ve stable field identity daha da önem kazanır. Nested array satırlarını tek dev component'ta render etmek performance ve okunabilirliği düşürebilir. API payload'ı nested yapıyı doğrudan kabul etmiyorsa submit öncesi normalize dönüşümü yapılabilir.
Nested Field Naming
Nested field name path yapısına göre örneğin `orders.0.items.1.quantity` gibi üretilebilir. TypeScript literal type inference bazı dinamik string template durumlarında ek type annotation isteyebilir. Name helper kullanılırken generated path'in okunabilir olması önemlidir. Field path'i UI label'dan değil domain modelinden türetilmelidir. Refactoring sırasında nested alan isimlerinin değişimi selector ve testlerde de güncellenmelidir.
Nested Validation
Nested schema her object ve array seviyesinde ayrı validation kuralları tanımlayabilir. Inner item hataları doğru path üzerinde üretildiğinde React Hook Form error tree üzerinden ilgili component'a ulaştırılabilir. Cross-level kural parent ve child değerlerini birlikte gerektiriyorsa object-level validation kullanılabilir. Çok derin error yapısını UI component'ların doğrudan çözmesine izin vermek yerine ortak error helper kullanılabilir. Server error mapping aynı nested field path convention'ını kullanırsa kullanıcıya doğru alan üzerinde feedback göstermek kolaylaşır.
Nested Error Mesajlarının Gösterilmesi
Nested error erişimi `errors.orders?.[index]?.items?.[itemIndex]?.quantity` gibi uzun path'lere dönüşebilir. Reusable field component name üzerinden ilgili error'ı çözebiliyorsa component kodu sadeleşir. Ancak magic string helper type güvenliğini kaybetmemelidir. Genel array error ile belirli input error görsel olarak farklı seviyede sunulabilir. Kullanıcı submit sonrası ilk hatalı nested alana scroll ve focus edildiğinde uzun formlarda hata düzeltme süresi kısalır.
Nested Formlarda Performans Sorunları
Nested formda root seviyede bütün değerleri watch etmek her child input değişiminde büyük component ağacını yeniden render edebilir. Row ve inner row component'ları küçük subscription'larla ayrılmalıdır. `useWatch` belirli nested path'e bağlanabilir. Çok büyük array'lerde virtualization değerlendirilebilir, ancak unmount edilen input'ların registration ve validation davranışı önceden test edilmelidir. Performance optimizasyonu önce profiler üzerinden gerçekten yavaş olan component'ı tespit ederek yapılmalıdır.
Koşullu ve Birbirine Bağımlı Form Alanları
Koşullu alanlar form değerleri arasındaki dependency'yi görünür hâle getirir. Bir seçim başka field'ı göstermenin yanında onun validation, default value ve payload davranışını da değiştirebilir. Basit bağımlılık `useWatch` ile izlenebilir. Çok sayıda field birbirini etkiliyorsa dependency graph açık bir domain logic katmanına taşınmalıdır. Koşullu UI ile schema doğrulamasının aynı kurala dayanması kullanıcıya görünmeyen stale değerlerin gönderilmesini engeller.
Conditional Field Nedir?
Conditional field belirli koşul gerçekleştiğinde gösterilen veya davranışı değişen form alanıdır. Kullanıcı “Şirket adına fatura” seçerse şirket adı ve vergi numarası alanlarının görünmesi buna örnektir. Alan gizlendiğinde değer korunabilir veya silinebilir, ancak bu karar business anlamına göre verilmelidir. Gizli değer submit edilmeyecekse unregister veya payload dönüşümü kullanılabilir. Conditional field logic'i yalnız JSX koşulu olarak yazılmamalı, validation ve API modeline etkisi de düşünülmelidir.
watch ve useWatch Arasındaki Fark
`watch` form değerlerini form instance seviyesinde izlemek için kullanılabilir ve bütün formu watch etmek root render davranışını genişletebilir. `useWatch` subscription'ı hook kullanılan component seviyesinde izole etmeye yardımcı olur. Büyük formda yalnız `country` değerini kullanan adres component'ı `useWatch({ name: 'country' })` yaklaşımıyla dar takip yapabilir. Root `watch()` kullanımını kolaylık için her yerde tercih etmek performans avantajını azaltabilir. Hangi değerin hangi component tarafından tüketildiği subscription kararının temelidir.
Bir Alanın Başka Alanları Kontrol Etmesi
Bir alan başka birkaç field'ın görünürlük, required veya seçenek listesini etkileyebilir. Bu tür dependency kuralları formun business davranışını temsil eder. Basit durumda component içinde birkaç condition yeterlidir. Dependency zinciri büyüdüğünde tek bir source of truth fonksiyonu veya domain configuration kullanmak gerekir. Böylece UI, validation ve API mapping aynı koşulları farklı şekillerde tekrar yazmaz.
Alan Gösterme/Gizleme
Alan görünürlüğü `useWatch` ile izlenen kontrol değerine göre belirlenebilir. Input gizlendiğinde form state'te kalıp kalmayacağı `shouldUnregister` veya manuel unregister kararıyla yönetilir. Kullanıcı alanı yeniden açtığında önceki değerin dönmesi bazı formlarda faydalı olabilir. Başka senaryoda eski değerin silinmesi business requirement'tır. UI davranışı product kararı olarak açıkça tanımlanmalıdır.
Alanı Required Hale Getirme
Bir field yalnız belirli koşulda required olabilir. Required yıldızını göstermek kadar validation schema'nın aynı koşulu uygulaması gerekir. HTML `required` attribute kullanıcıya browser feedback sağlayabilir, ancak server validation'ın yerine geçmez. Koşul değiştiğinde mevcut error state gerekiyorsa yeniden validate edilebilir. Kullanıcı artık gerekli olmayan alanda eski hata görmemelidir.
Dinamik Option Listeleri
Ülke seçimine göre şehir listesi veya ürün seçimine göre varyant listesi değişebilir. Parent değer değiştiğinde child seçim artık geçerli olmayabilir ve temizlenmesi gerekebilir. Option list server state ise query key parent field değerini içerebilir. Eski request'in geç dönüp yeni seçenekleri ezmemesi için cancellation veya request identity yönetilmelidir. Loading ve empty state kullanıcıya açık biçimde gösterilmelidir.
unregister Kullanımı
`unregister` field'ı form registration'dan çıkarmak için kullanılır. Conditional field artık formun parçası olmayacaksa eski değerin submit edilmesini önlemek için yararlı olabilir. Ancak unregister sonrası kullanıcı alanı tekrar açtığında önceki değer kaybolabilir. Bu nedenle kullanım kararı UX gereksinimiyle birlikte verilmelidir. Global `shouldUnregister` seçeneği bütün form davranışını değiştirdiği için büyük wizard ve conditional form'larda dikkatle test edilmelidir.
Gizlenen Alanların Eski Değerlerini Temizlemek
Gizlenen alanın eski değeri payload'a gönderildiğinde backend kullanıcının artık görmediği bilgiyi işlemeye devam edebilir. Bu özellikle permission veya form mode değişiminde risklidir. Field unregister edilebilir veya `setValue` ile güvenli default'a çekilebilir. Alternatif olarak `toApiPayload` yalnız aktif alanları dahil edebilir. Temizleme stratejisi form state ve API adapter arasında tek yerde standardize edilmelidir.
Karmaşık Dependency Graph Yönetimi
Bir field beş alanı, onların her biri de başka alanları etkiliyorsa component içindeki effect zincirleri yönetilemez hâle gelebilir. Dependency graph domain rule fonksiyonları, derived selectors veya state machine benzeri explicit modele taşınabilir. Hesaplanabilen görünürlük state'i ayrıca form value olarak saklanmamalıdır. Rule engine kullanımı ancak gerçek tekrar ve configuration ihtiyacı varsa düşünülmelidir. Basit koşulları aşırı generic sisteme taşımak da geliştirme hızını düşürebilir.
Controller ve Controlled Component Entegrasyonu
React Hook Form native input'larda register yaklaşımıyla çok rahat çalışırken bazı UI kütüphaneleri controlled component API'si sunar. `Controller` ve `useController` bu component'ların value, onChange, onBlur ve ref davranışını form kontrolüne bağlar. Her input için Controller kullanmak gerekli değildir. Controlled component integration gerçek ihtiyaç olduğunda tercih edilmelidir. Ortak wrapper component'lar kütüphane detaylarını domain form component'larından gizleyebilir.
Controller Nedir?
`Controller`, controlled input component ile React Hook Form arasındaki adapter rolünü üstlenir. Render prop üzerinden `field` ve field state bilgilerini sağlar. UI component'ın `value` ve `onChange` API'si field nesnesiyle eşleştirilir. Date picker veya custom select gibi native register contract'ına uymayan input'larda kullanışlıdır. Component API farklı değer formatı kullanıyorsa mapping aynı adapter içinde yapılabilir.
Controller Ne Zaman Kullanılmalı?
UI component değerini dışarıdan `value` prop ile alıyor ve kendi özel `onChange` imzasını kullanıyorsa Controller uygun seçimdir. Material UI Select, bazı date picker ve rich text editor bileşenleri buna örnek olabilir. Component ref forwarding ve native name davranışı register için yeterli değilse de Controller tercih edilebilir. Wrapper bir kez yazılıp design system içinde tekrar kullanılabilir. Controlled integration'ın value transformation davranışı TypeScript type'larıyla açık tutulmalıdır.
Controller Ne Zaman Kullanılmamalı?
Native `input`, `select` veya doğrudan ref kabul eden basit component register ile rahatça kullanılabiliyorsa Controller eklemek gereksizdir. Her field'ı Controller ile sarmak daha fazla component katmanı ve controlled render davranışı oluşturabilir. Library API'sinin en güçlü yönlerinden biri register ile düşük maliyetli integration sağlamasıdır. Tek tip abstraction uğruna bütün input'ları controlled hâle getirmek doğru optimizasyon değildir. Form component standardı register-first, gerektiğinde Controller şeklinde kurulabilir.
useController ile Alan İzolasyonu
`useController` Controller'ın hook tabanlı alternatifidir ve custom field component içinde daha doğrudan integration sağlar. Field value, change handler ve field state component scope'unda alınabilir. Reusable design system input'ları için bu yaklaşım render prop nesting'i azaltabilir. Hook kullanan component kendi form subscription'ını yönetir. Generic type ve `FieldPath` ile type-safe reusable field API oluşturulabilir.
Material UI Entegrasyonu
Material UI component'larının önemli bölümü controlled API kullanabilir ve Controller ile rahat bağlanabilir. TextField bazı senaryolarda register ile de entegre edilebilir, bu nedenle component türüne göre en sade yaklaşım seçilmelidir. Error ve helper text React Hook Form field error bilgisinden türetilebilir. Date veya Autocomplete gibi complex component'larda value mapping açık yapılmalıdır. Design system wrapper oluşturmak feature component'ların Material UI ayrıntılarına doğrudan bağımlılığını azaltır.
Ant Design Entegrasyonu
Ant Design form component'ları kendi form abstraction'ına sahip olsa da React Hook Form ile Controller üzerinden kullanılabilir. İki form state sistemini aynı anda source of truth olarak kullanmak kaçınılması gereken bir durumdur. Ant component yalnız UI input olarak kullanılacaksa value ve onChange React Hook Form tarafından yönetilebilir. Validation mesajı tek sistemden gelmelidir. Table içindeki editable cell gibi complex senaryolar integration test ile doğrulanmalıdır.
shadcn/ui Entegrasyonu
shadcn/ui yaklaşımında component kodu proje içinde bulunduğu için React Hook Form integration'ı doğrudan özelleştirilebilir. Native Input register ile kullanılabilirken Select veya custom controlled component Controller isteyebilir. Form item, label, description ve message pattern'i reusable wrapper'a dönüştürülebilir. Kod ownership ekipte olduğu için generic type ve accessibility behavior kurum standardına göre güçlendirilebilir. Generated örnek kodlar production form architecture'ına alınmadan önce domain ve validation sınırları açısından gözden geçirilmelidir.
Date Picker ve Select Component'leri
Date picker ve select component'ları value formatı bakımından normal input'tan farklı olabilir. Date picker Date object döndürürken API ISO string bekleyebilir. Form modelinde hangi formatın tutulacağı açıkça belirlenmeli ve API mapping ayrı yapılmalıdır. Select option object yerine yalnız id saklamak bazı formlarda daha sade payload sağlar. Controller adapter bu dönüşümü UI component ile form state arasında tek yerde yönetebilir.
Masked Input ve Rich Text Editor
Masked input kullanıcıya biçimli değer gösterirken form veya API için normalize edilmiş değer üretmek isteyebilir. Rich text editor ise string HTML, JSON document veya editor-specific model döndürebilir. Bu component'lar controlled integration ve value transformation gerektirir. Rich text içeriği server tarafında güvenli biçimde sanitize edilmelidir. Büyük editor package'ları lazy load edilerek formun ilk açılış bundle maliyeti azaltılabilir.
FormProvider ve useFormContext ile Büyük Formları Yönetmek
FormProvider büyük formu section component'lara ayırırken bütün `useForm` method'larını prop zinciriyle taşımayı önler. Child component `useFormContext` üzerinden mevcut form instance'a erişebilir. Bu yaklaşım her component'ın formun tamamını izlemesi gerektiği anlamına gelmez. Value subscription yine `useWatch`, `useController` veya `useFormState` gibi dar hook'larla yapılmalıdır. Context form dependency injection için kullanıldığında component yapısı sadeleşir ve reusable field'lar daha kolay geliştirilir.
Prop Drilling Problemi
Root formdan dört seviye aşağıdaki input'a `register`, `control`, `errors` ve `setValue` taşımak component API'sini form altyapısına bağımlı hâle getirir. Aradaki component'lar kendilerinin kullanmadığı prop'ları yalnız geçirmek zorunda kalır. FormProvider bu dependency'yi context üzerinden sağlar. Böylece section component yalnız business props'unu alabilir. Çok geniş global context yerine provider yalnız ilgili form subtree'sini sarmalıdır.
FormProvider Nasıl Kullanılır?
FormProvider `useForm` tarafından döndürülen method'ları provider value olarak child ağaca sunar. Root form component `const methods = useForm()` oluşturup FormProvider ile form section'larını sarabilir. Child component'lar aynı form lifecycle'ı içinde çalışır. Nested farklı FormProvider'lar yalnız gerçekten ayrı form instance gerektiğinde kullanılmalıdır. Provider'ın form element'iyle aynı şey olmadığı unutulmamalı ve submit ownership root'ta açık tutulmalıdır.
useFormContext Nasıl Kullanılır?
`useFormContext` en yakın FormProvider içindeki form method'larına erişir. Reusable field component register veya control bilgisini buradan alabilir. Component'ın hangi form modelinde kullanılacağını generic type ile ifade etmek type güvenliğini artırır. Her component `formState` tamamını okumamalıdır. Yalnız gerektiğinde ilgili method veya subscription hook kullanılmalıdır.
Typed Form Context Oluşturmak
Generic field component'larda context type'ını korumak dikkat gerektirir. Component `TFieldValues extends FieldValues` generic'i ve `FieldPath` name prop'u kullanabilir. Feature-specific field'larda generic yerine doğrudan `CustomerFormValues` gibi type kullanmak daha okunabilir olabilir. Type abstraction yalnız yeniden kullanım gerçekse oluşturulmalıdır. Aşırı generic component API'si TypeScript hata mesajlarını ve kullanımını zorlaştırabilir.
Reusable Field Component Tasarımı
Reusable field component label, input bağlantısı, açıklama ve error gösterimini standardize eder. Component'ın işi business validation üretmek değil mevcut field state'i doğru biçimde sunmaktır. Design system input ile React Hook Form integration ayrı katmanlarda da tutulabilir. Accessibility attribute'ları component içinde ortaklaştırıldığında bütün projede daha tutarlı davranış elde edilir. Yeni field türleri mevcut abstraction'a uymuyorsa component API'sini zorlamak yerine özel adapter geliştirmek daha doğru olabilir.
Label
Label input'un amacını kullanıcıya açıkça anlatmalıdır. `htmlFor` ile input id eşleştirilmelidir. Required bilgisi yalnız yıldız sembolüne bırakılmamalıdır. Label metni business terminolojisine uygun ve mümkün olduğunca kısa olmalıdır. Reusable component her field'da aynı label spacing ve typography davranışını sağlar.
Input
Input doğru semantic element'i kullanmalıdır. Type, autocomplete ve inputMode gibi browser özellikleri kullanıcı deneyimini iyileştirebilir. Form register veya controlled field binding bu component seviyesinde yapılabilir. Disabled ile read-only anlamı birbirinden farklıdır ve doğru kullanılmalıdır. Input component yalnız visual style değil focus ve error state davranışını da standardize etmelidir.
Help Text
Help text kullanıcıya alan formatı veya beklenen değeri submit öncesinde açıklar. Error mesajıyla aynı şeyi tekrar etmemelidir. Çok uzun açıklamalar formu kalabalıklaştırabilir. Yardım metni input ile `aria-describedby` üzerinden ilişkilendirilebilir. Dynamic requirement varsa help text koşula göre güncellenebilir.
Error
Error kullanıcıya yalnız “geçersiz” demek yerine neyi düzeltmesi gerektiğini anlatmalıdır. Field error input'a programatik olarak bağlanmalıdır. Aynı error hem inline hem toast olarak gösterilirse gereksiz tekrar oluşabilir. Form-level error ayrı bir bölgede gösterilebilir. Backend error code kullanıcı dostu metne UI katmanında çevrilebilir.
Accessibility Attributes
Hatalı input `aria-invalid` ile işaretlenebilir. Açıklama veya error element id'si `aria-describedby` üzerinden input'a bağlanabilir. Dynamic error `role="alert"` gibi uygun live region davranışıyla screen reader'a duyurulabilir. Her field için gereksiz ARIA eklemek yerine native semantic HTML temel alınmalıdır. Design system component'ı bu davranışları ortaklaştırarak feature geliştiricinin hata yapma ihtimalini azaltır.
Context Kaynaklı Re-render Sorunlarını Önlemek
FormProvider bütün form method'larını paylaşsa da child component'ın yeniden render davranışı kullandığı subscription'a bağlıdır. Root seviyede formState veya watch ile bütün formu dinleyen component geniş render zinciri oluşturabilir. Child section `useFormState({ name })` veya `useWatch({ name })` ile yalnız gerekli alanları izleyebilir. Reusable field component kendi field state'ine subscribe olabilir. React Profiler büyük formda hangi component'ın gereksiz render aldığını göstermek için düzenli kullanılmalıdır.
Çok Adımlı Form ve Wizard Yönetimi
Wizard form uzun business süreçlerini kullanıcı için daha küçük ve anlaşılır adımlara böler. Mimari kararların başında tek bir `useForm` instance mı yoksa her adımda ayrı form mu kullanılacağı gelir. Tek instance bütün değerleri bir arada tutmayı ve final validation'ı kolaylaştırır. Ayrı instance yaklaşımı adımları bağımsızlaştırabilir fakat state taşıma ve validation birleşimi için ek yapı gerektirir. Seçim adımların birbirine ne kadar bağlı olduğu ve route bazında ayrılıp ayrılmadığına göre yapılmalıdır.
Tek useForm mı, Her Adıma Ayrı useForm mu?
Adımlar aynı business entity'nin tek submit payload'ını oluşturuyorsa tek `useForm` çoğu zaman daha sade olur. Önceki adımların değerleri aynı form state'te korunur ve final submit bütün modeli doğrudan kullanabilir. Adımlar farklı route'larda ve bağımsız server kayıtları olarak ilerliyorsa her adım için ayrı form daha uygun olabilir. Ayrı form kullanıldığında draft veya workflow store ortak state'i taşır. Karar UI tasarımından çok data lifecycle ve save semantics üzerinden verilmelidir.
Tek Form State ile Wizard Tasarımı
Tek form instance root wizard component veya layout seviyesinde oluşturulur. Step component'ları FormProvider üzerinden aynı state'e erişir. Aktif step bilgisi form value değil local UI veya workflow state olarak tutulabilir. Hidden step field'larının registration davranışı `shouldUnregister` kararına göre değişir. Final submit bütün form modelini schema üzerinden tekrar doğrular.
trigger ile Adım Bazlı Validation
`trigger` belirli field veya field gruplarının validation'ını programatik olarak çalıştırabilir. Kullanıcı “İleri” butonuna bastığında yalnız mevcut adıma ait field'lar doğrulanabilir. Validation başarılıysa step state ilerletilir. Step field listeleri domain configuration içinde tutulursa UI ve validation aynı grubu kullanabilir. Final adımda yalnız son step değil bütün form yeniden doğrulanmalıdır.
Önceki Adımların Değerlerini Korumak
Wizard kullanıcı geri döndüğünde önceki girişlerini kaybetmemelidir. Tek useForm ve unregister edilmeyen alanlar bu davranışı doğal biçimde sağlar. Route bazlı wizard'da form state context veya draft storage üzerinden korunabilir. Sensitive değerlerin localStorage gibi persistence katmanına yazılması uygun olmayabilir. Kullanıcının uzun süreçte session süresi dolarsa draft recovery davranışı ayrıca planlanmalıdır.
shouldUnregister Stratejisi
`shouldUnregister` unmount edilen alanların form state'ten çıkarılıp çıkarılmayacağını etkiler. Wizard'da true kullanılırsa önceki step component unmount olduğunda değerleri kaybolabilir. False yaklaşımı görünmeyen step değerlerini korumayı kolaylaştırabilir. Conditional field'larda ise eski değerlerin kalması istenmeyebilir. Global ayar yerine business ihtiyacına göre form yapısı ve gerektiğinde manuel unregister birlikte kullanılmalıdır.
Progress Indicator Tasarımı
Progress indicator kullanıcıya kaç adım kaldığını ve mevcut konumunu gösterir. Yalnız dekoratif yüzde yerine step isimleri çoğu business formda daha anlaşılırdır. Tamamlanmamış step'e serbest navigation izin verilip verilmeyeceği workflow kuralına bağlıdır. Screen reader kullanıcıları mevcut step bilgisini programatik olarak anlayabilmelidir. Mobile görünümde uzun step listesi daha kompakt sunulabilir.
Son Adımda Tüm Formun Yeniden Doğrulanması
Kullanıcı önceki adımı geçtikten sonra dependency veya server data değişmiş olabilir. Bu nedenle final submit bütün schema'yı yeniden doğrulamalıdır. Client validation başarılı olsa bile backend bütün business kurallarını tekrar çalıştırır. Error eski step'e aitse wizard kullanıcıyı ilgili adıma götürebilir. Hata özeti hangi step'in düzeltme istediğini açıkça göstermelidir. Bu davranış özellikle uzun kurumsal başvuru süreçlerinde kullanıcı hatasını azaltır.
Form Draft ve Autosave Yönetimi
Uzun formlarda kullanıcının yarım saatlik girişini tarayıcı yenilenmesi veya network problemi nedeniyle kaybetmesi ciddi kullanıcı deneyimi sorunudur. Draft local browser storage veya server üzerinde saklanabilir. Hangi yöntemin kullanılacağı veri hassasiyeti, multi-device devam ve conflict ihtiyacına bağlıdır. Autosave dirty alanları belirli debounce süresiyle gönderebilir. Race condition ve version conflict çözülmeden autosave eklemek kayıp riskini azaltmak yerine görünmez veri ezilmesine yol açabilir.
Uzun Formlarda Draft Neden Gereklidir?
Başvuru, teklif veya kapsamlı profil formları tek oturumda tamamlanmayabilir. Kullanıcı başka sayfaya geçebilir, oturumu kapanabilir veya cihaz değiştirmek isteyebilir. Draft özelliği tamamlanmamış veriyi kaydederek bu süreci güvenli hâle getirir. Draft ile final submit aynı business status olarak değerlendirilmemelidir. Backend incomplete data'nın validation ve permission modelini final kayıt modelinden ayrı yönetebilir.
LocalStorage ile Draft Saklamak
LocalStorage düşük riskli ve cihazda kalması kabul edilen draft'lar için kolay çözüm sunar. React Hook Form değerleri belirli aralıkta serialize edilerek storage'a yazılabilir. Büyük object ve sık write işlemleri synchronous localStorage API nedeniyle main thread'i etkileyebilir. Schema version bilgisi saklanmalıdır. Hassas kişisel veri ve credential localStorage için uygun değildir.
Hangi Veriler Saklanmalı?
Kullanıcının kaybolması durumunda tekrar girmesi zahmetli olan düşük riskli alanlar draft için adaydır. Formun business durumuna göre metin, seçim ve yapılandırma değerleri saklanabilir. Gereksiz derived state storage'a yazılmamalıdır. File object gibi serialize edilmesi zor değerler farklı strateji gerektirir. Storage whitelist yaklaşımı bütün formu körü körüne kaydetmekten daha güvenlidir.
Hangi Veriler Saklanmamalı?
Şifre, access token, ödeme bilgisi veya yüksek hassasiyetli kişisel veri localStorage draft içinde tutulmamalıdır. Server-owned reference data tekrar fetch edilebilir ve saklanmasına gerek yoktur. Loading, error veya open modal gibi UI state de draft'ın parçası değildir. File binary data normal JSON storage'a uygun değildir. Her field için persistence ihtiyacı data classification ile birlikte değerlendirilmelidir.
Server-Side Draft Kaydetme
Server draft kullanıcıya farklı cihazdan devam etme imkânı sağlar. Draft authenticated user ve tenant scope içinde saklanmalıdır. Her autosave full payload veya yalnız değişen field'ları gönderebilir. Version numarası concurrent edit conflict'i tespit etmeye yardımcı olur. Final submit draft status'u tamamlanmış business kaydına dönüştürebilir.
dirtyFields ile Değişen Alanları Bulmak
`dirtyFields` kullanıcının default değerlerden farklılaştırdığı alanları gösterir. Autosave yalnız değişen alanları göndermek istiyorsa faydalı bir sinyal olabilir. Nested object ve array dirty yapısı dikkatle payload'a dönüştürülmelidir. Bir field eski değerine geri döndüğünde dirty davranışı default value comparison'a bağlıdır. Server patch endpoint ile form dirty modeli aynı semantics üzerinde anlaşmalıdır.
Debounce ile Autosave
Her keypress'te server'a autosave göndermek gereksiz request sayısı oluşturur. Debounce kullanıcı kısa süre yazmayı bıraktığında tek request başlatır. Süre çok uzun olursa veri kaybı penceresi büyür, çok kısa olursa backend yükü artar. Formun text ve toggle field'ları için farklı save stratejisi kullanılabilir. Kullanıcı sayfadan ayrılırken pending save'in durumu açıkça yönetilmelidir.
Race Condition Yönetimi
Autosave request A başladıktan sonra kullanıcı yeni değişiklik yapıp request B'yi başlatabilir. B önce tamamlanır, ardından A geç cevap verirse server eski değerle yeni draft'ı ezebilir. Request version, sequence number veya optimistic concurrency token kullanılabilir. Client yalnız son başarılı request'i güncel durum olarak gösterebilir. Server da stale version update'ini reddederek veri bütünlüğünü korumalıdır.
Draft Versiyonlama ve Conflict Yönetimi
Kullanıcı aynı formu iki tab veya cihazda açtığında draft conflict oluşabilir. Server her draft revision için version veya updatedAt bilgisi tutabilir. Update eski version ile gelirse 409 benzeri conflict response dönebilir. UI kullanıcıya iki version'ı karşılaştırma veya yeniden yükleme seçeneği sunabilir. Otomatik last-write-wins basit görünse de önemli kurumsal veride sessiz data kaybına yol açabilir.
API'den Gelen Verilerle Edit Formu Oluşturmak
Edit formu create formundan daha fazla lifecycle yönetimi gerektirir çünkü initial değerler asenkron gelir. API modeli UI'nın ihtiyaç duyduğu form modelinden farklı olabilir. Tarih, nullable değer, option object ve nested entity'ler `toFormValues` benzeri adapter ile dönüştürülebilir. React Hook Form `reset` veya async default values yaklaşımıyla formu hydrate edebilir. Kullanıcı edit yapmaya başladıktan sonra background refetch'in formu sessizce resetlememesi conflict stratejisinin önemli parçasıdır.
Async Default Values
`useForm` default value kaynağı asenkron veriyle ilişkilendirilebilir. Bu yaklaşım loading state ve form mount timing'ini sadeleştirebilir. Alternatif olarak data query tamamlandıktan sonra `reset` kullanılabilir. Hangi model seçilirse seçilsin uncontrolled input'ların başlangıç değerleri tutarlı olmalıdır. Default values form lifecycle boyunca referans noktası olduğu için dirty state hesabını da etkiler.
API Verisini Form Modeline Dönüştürme
API response doğrudan form value olarak kullanılmamalıdır. Backend null döndürürken input boş string bekleyebilir veya timestamp Date picker için farklı formata çevrilebilir. İlişkili entity object'i formda yalnız id olarak tutulabilir. Bu dönüşüm ayrı pure function olduğunda unit test yazmak kolaylaşır. Backend contract değiştiğinde UI component'ların tamamı yerine adapter güncellenebilir.
reset ile Formu Hydrate Etmek
API data geldikten sonra `reset(toFormValues(data))` formun değerlerini ve default baseline'ını güncelleyebilir. Bu yöntem edit ekranında sık kullanılır. Query background refetch olduğunda otomatik reset kullanıcı değişikliklerini silebilir, bu nedenle yalnız initial load veya explicit refresh sırasında çalıştırılmalıdır. Dirty form varsa server'dan yeni version geldiğinde conflict mesajı gösterilebilir. Reset seçenekleri touched veya dirty bilgiyi korumak gerektiğinde bilinçli kullanılmalıdır.
Create ve Edit Modunu Tek Component'te Yönetmek
Create ve edit ekranları aynı field yapısını paylaşıyorsa ortak form component kullanılabilir. Parent mode'a göre initial values ve submit service belirleyebilir. Mode kontrollerinin her input içine dağılması component'ı zorlaştırabilir. Bazı field'lar create sırasında zorunlu, edit sırasında read-only olabilir ve schema mode'a göre üretilebilir. İki flow zamanla çok farklılaşırsa sırf tekrar azaltmak için tek component'ta tutmak yanlış abstraction'a dönüşebilir.
API Modeli ile Form Modelini Ayırmak
API modeli backend storage veya transport ihtiyacına göre şekillenir. Form modeli ise kullanıcı etkileşimine uygun değerleri temsil eder. Örneğin API para değerini minor unit integer olarak tutarken form ondalık string gösterebilir. Bu iki modeli ayırmak UI'yı backend implementation detayından korur. Adapter fonksiyonları dönüşümü açık ve test edilebilir hâle getirir.
toFormValues
`toFormValues` API veya domain entity'yi formun beklediği shape'e dönüştüren pure function olarak tasarlanabilir. Null değerleri güvenli default'a çevirir, tarih formatını düzenler ve nested reference'ları select value'ya dönüştürür. Bu fonksiyon React component dışında test edilebilir. Create form için ayrı `createDefaultValues` factory kullanılabilir. Mapping logic'i component JSX içine dağıtmak yerine tek noktada tutmak backend değişikliklerini daha kolay yönetir.
toApiPayload
`toApiPayload` valid form değerlerini backend request modeline dönüştürür. UI-only field'lar payload'dan çıkarılır. Tarih, para ve file reference gibi değerler API formatına normalize edilir. Hidden veya conditional alanlar business kurala göre temizlenebilir. Dönüşümün pure function olması API contract testlerini ve create/edit farklarını yönetmeyi kolaylaştırır.
React Hook Form ile API Submission Yönetimi
Form submission yalnız `fetch` çağrısı yapmak değildir. Validation, double submit koruması, loading, error mapping, retry ve success navigation birlikte tasarlanmalıdır. `handleSubmit` client validation tamamlandıktan sonra application submit handler'ını çalıştırır. Backend yine payload'ı doğrular ve business conflict'leri uygun error contract ile döndürür. Submission lifecycle kullanıcıya işlemin hangi durumda olduğunu açık biçimde göstermelidir.
handleSubmit Akışı
`handleSubmit` form values'i validation sürecinden geçirip success callback'e aktarır. Callback önce `toApiPayload` ile API modelini oluşturabilir. Network logic ayrı mutation hook veya service üzerinden çalıştırılabilir. Validation error durumunda request gönderilmez. Submit callback'in kendisi server error handling ve navigation gibi side effect'leri yönetmek için açık orchestration noktasıdır.
Loading State
Submit sırasında kullanıcı işlemin devam ettiğini anlamalıdır. `formState.isSubmitting` async submit lifecycle için kullanılabilir. Button disable edilip loading label gösterilebilir. Bütün formu gereksiz şekilde disabled hâle getirmek kullanıcıya veri kontrolü yapma imkânını azaltabilir. Uzun süren işlemde progress veya açıklayıcı mesaj kullanılması daha iyi deneyim sağlar.
Double Submit Önleme
Kullanıcının submit button'a hızlıca iki kez basması duplicate request oluşturabilir. Client button loading sırasında disable edilebilir. Bununla birlikte gerçek koruma server tarafında idempotency veya duplicate detection ile sağlanmalıdır. Network retry de kullanıcı iki kez basmasa bile aynı operation'ın tekrar gönderilmesine yol açabilir. Kritik create veya payment işlemlerinde idempotency key güçlü bir güvence sağlar.
Success State
Başarı sonrasında kullanıcı ne olduğunu ve sonraki adımı açıkça görmelidir. Form reset, detay sayfasına yönlendirme veya success banner business flow'a göre seçilir. Optimistic UI kullanılmışsa server canonical result ile state reconcile edilmelidir. Analytics success event yalnız backend işlemi gerçekten tamamlandığında gönderilmelidir. Autosave formunda success durumu daha sessiz “Kaydedildi” indicator biçiminde sunulabilir.
Error State
Error state field-level ve form-level olarak ayrılmalıdır. Validation hatası ilgili input yanında gösterilirken network outage form üstünde genel mesaj gerektirebilir. Teknik stack trace kullanıcıya gösterilmemelidir. Retry edilebilir ve edilemez hata türleri farklı UX taşımalıdır. Error telemetry correlation id ile backend log'una bağlanabiliyorsa production debugging hızlanır.
Idempotent Submission
Idempotency aynı operation birden fazla kez gönderildiğinde duplicate business sonucu oluşmasını engellemeyi hedefler. Client unique idempotency key üretip request ile server'a gönderebilir. Server daha önce aynı key ile tamamlanan operation'ı tekrar yaratmak yerine önceki sonucu döndürebilir. Bu özellikle ödeme, sipariş ve başvuru oluşturma gibi kritik işlemlerde değerlidir. Form library bu davranışı otomatik çözmez ve API contract'ın parçası olarak tasarlanmalıdır.
Retry Stratejisi
Geçici network hatası retry ile çözülebilir, ancak validation veya conflict hatası tekrar denemeyle düzelmez. Mutation library response türüne göre retry policy uygulayabilir. Otomatik retry idempotent olmayan operation'larda duplicate risk oluşturabilir. Kullanıcıya manuel tekrar deneme seçeneği vermek bazı kritik formlarda daha güvenlidir. Retry count ve failure telemetry backend reliability değerlendirmesinde izlenebilir.
Backend Validation Hatalarını Forma Aktarmak
Client schema kullanıcıya hızlı feedback sağlar fakat gerçek verinin geçerliliğine son kararı server vermelidir. Database uniqueness, authorization, güncel stok veya business workflow state'i yalnız browser'da güvenilir biçimde doğrulanamaz. Backend error contract field error ve form-level error ayrımını desteklerse React Hook Form'a mapping kolaylaşır. `setError` server field hatasını ilgili input'a bağlayabilir. Kullanıcı teknik database mesajı yerine anlaşılır ve eyleme dönük hata görmelidir.
Client Validation Neden Tek Başına Yeterli Değildir?
Browser kodu kullanıcı tarafından değiştirilebilir veya API doğrudan çağrılabilir. Client validation yalnız kullanıcı deneyimini iyileştiren erken kontrol katmanıdır. Başka bir kullanıcı form açıkken aynı e-posta adresini kaydetmiş olabilir. Permission veya business state de client render'dan sonra değişebilir. Server bütün güvenlik ve kalıcı veri kurallarını request sırasında yeniden doğrulamalıdır.
Server-Side Validation
Server input type, format, permission ve business constraint'leri doğrular. Schema validation ile temel payload kontrolü yapılabilir. Database veya external service gereken kurallar application service katmanında çalıştırılır. Hatalar predictable contract ile client'a döndürülmelidir. Internal exception ile kullanıcı kaynaklı validation error birbirinden ayrılmalıdır.
API Error Contract Tasarımı
İyi error contract frontend'in string parsing yapmadan hatayı sınıflandırmasına izin verir. Field path, error code ve kullanıcı mesajı ayrı alanlar olabilir. Form-level conflict belirli input'a bağlı olmayan ayrı error listesinde dönebilir. Nested field array hataları backend ile frontend aynı field path convention'ını kullanıyorsa kolay eşlenir. Contract version veya backward compatibility büyük client ekosisteminde ayrıca düşünülmelidir.
Field Errors
Field error belirli input ile ilişkilidir. API response örneğin `email` field path'i ve `EMAIL_ALREADY_USED` code'u döndürebilir. Frontend `setError('email', ...)` ile mesajı doğru input yanında gösterir. Kullanıcı aynı alanı değiştirdiğinde server error'ın ne zaman temizleneceği açık olmalıdır. Nested array path'leri de aynı modelle ifade edilebilir.
Form-Level Errors
Form-level error tek input'a bağlanamayan business problemini ifade eder. “Bu kayıt başka kullanıcı tarafından güncellendi” veya genel permission değişikliği buna örnektir. React Hook Form root error alanı veya ayrı application error state kullanılabilir. Hata formun üstünde görünür ve kullanıcıya sonraki aksiyonu anlatır. Field error'ları tek genel toast'a çevirmek düzeltme deneyimini zorlaştırır.
Machine-Readable Error Codes
Machine-readable code frontend'in backend mesaj metnini parse etmeden davranış seçmesini sağlar. `DUPLICATE_EMAIL`, `VERSION_CONFLICT` veya `LIMIT_EXCEEDED` gibi kodlar localization ve analytics için de değerlidir. Kullanıcı mesajı frontend tarafında çevrilebilir veya server localization modeline göre dönebilir. Code contract dokümante edilmelidir. Internal database hata kodu doğrudan public API code olarak expose edilmemelidir.
setError Kullanımı
`setError` programatik olarak form error eklemeye izin verir. Backend field validation sonucu bu API ile ilgili field'a bağlanabilir. Error type server veya manual gibi semantic değer taşıyabilir. Kullanıcı field'ı düzelttiğinde error temizleme davranışı validation akışına göre yönetilir. Server error mapping helper bütün form feature'larında aynı contract'ı kullanarak tekrar azaltabilir.
root Error Kullanımı
Belirli input'a ait olmayan submit hataları root seviyesinde tutulabilir. Network failure, permission veya generic server validation buna örnektir. Root error formun üst kısmında alert olarak gösterilebilir. Yeni submit denemesinde eski root error temizlenmelidir. Aynı hata hem toast hem inline root alert olarak gereksiz tekrar edilmemelidir.
HTTP 400, 409 ve 422 Hatalarının Yönetimi
400 malformed request veya genel client error için kullanılabilir. 422 semantik validation hatalarını ifade etmek için bazı API tasarımlarında tercih edilir. 409 resource conflict veya optimistic concurrency problemi için anlamlıdır. Frontend yalnız status code'a değil structured error code'a da bakmalıdır. API standardı kurum genelinde tutarlı olduğunda form error mapping daha kolay reusable hâle gelir.
Database Constraint Hatalarının Kullanıcıya Gösterilmesi
Database unique constraint exception'ını doğrudan kullanıcıya göstermek güvenlik ve UX açısından doğru değildir. Backend constraint'i domain error'a çevirmelidir. Örneğin unique email violation kullanıcıya “Bu e-posta zaten kullanılıyor” şeklinde dönüştürülebilir. Database tablo veya constraint isimleri public response'a sızdırılmamalıdır. Frontend machine-readable code üzerinden doğru field error'ı oluşturabilir.
React Hook Form ve Next.js Entegrasyonu
Next.js App Router ile React Hook Form kullanırken form interaction'ı Client Component içinde yaşar. Server Actions mutation ve server-side validation için ayrı backend boundary sunabilir. Client schema kullanıcıya hızlı feedback verirken Server Action aynı veya daha güçlü kuralları tekrar çalıştırmalıdır. Server error sonucu React Hook Form `setError` API'sine map edilebilir. Progressive enhancement gereksinimi yüksek formlarda native form action yaklaşımı ile React Hook Form'un ne kadar birlikte kullanılacağı use case'e göre seçilmelidir.
Client Component İçinde React Hook Form
React Hook Form hook kullandığı için form controller Client Component içinde oluşturulur. Parent Server Component reference data'yı veya edit record'u serializable props olarak iletebilir. Client component bu data'yı default form values'a dönüştürür. Büyük sayfanın tamamını `'use client'` yapmak gerekmez. Yalnız form ve interactive subtree client boundary altında tutulabilir.
Server Actions ile Form Submission
Next.js Server Actions server tarafında mutation fonksiyonu çalıştırmaya ve native FormData kullanmaya izin verir. React Hook Form submit handler valid data'yı Server Action'a veya action wrapper'a iletebilir. Server Action input'u tekrar doğrulamalı ve authorization kontrolü yapmalıdır. Mutation sonrası cache revalidation veya redirect uygulanabilir. Client-heavy complex form ile native progressive form farklı ihtiyaçlara sahip olduğu için entegrasyon modeli proje bazında seçilmelidir.
Client + Server Çift Doğrulama
Client validation kullanıcı hatasını submit öncesinde gösterir. Server validation güvenlik ve business doğruluğunu garanti eder. Aynı Zod schema'nın ortak package içinde paylaşılması bazı kurallar için drift'i azaltabilir. Server-specific permission ve database kontrolü yine ayrı kalır. Client schema server'ın daha zayıf kopyası değil UX katmanı olarak görülmelidir.
Server Hatalarını React Hook Form'a Aktarmak
Server Action structured field error object döndürebilir. Client bu sonucu `setError` ile ilgili field'lara map edebilir. Root-level error form genelinde gösterilebilir. Server Action exception'ı doğrudan kullanıcı mesajı olarak kullanılmamalıdır. Reusable mapper Next.js action response contract ile React Hook Form error modelini birleştirebilir.
Progressive Enhancement
Next.js Server Components içindeki native form Server Action'a JavaScript yüklenmeden önce bile submit edilebilir. React Hook Form ise zengin client interaction ve instant validation için JavaScript'e ihtiyaç duyar. Kritik basit formda native Server Action yaklaşımı yeterli olabilir. Karmaşık wizard veya dynamic array formunda client form library daha fazla değer sağlar. Progressive enhancement seviyesi gerçek kullanıcı ve bağlantı gereksinimine göre belirlenmelidir.
Authentication ve Authorization Kontrolleri
Server Action kullanıcının authenticated olup olmadığını ve ilgili operation'a yetkisini her çağrıda doğrulamalıdır. Client form field'larını permission'a göre gizlemek yalnız UX kontrolüdür. Hidden field veya button kaldırılması server güvenliğinin yerine geçmez. Tenant id gibi güvenlik context'i doğrudan client payload'ına güvenilerek kullanılmamalıdır. Server session ve resource ownership aynı mutation içinde kontrol edilmelidir.
React Query / TanStack Query ile React Hook Form Kullanımı
TanStack Query server state lifecycle'ını, React Hook Form ise kullanıcı tarafından düzenlenen form draft'ını yönetir. İki araç aynı state'in sahibi olmaya çalışmadığında birlikte oldukça iyi çalışır. Query edit formunun initial data'sını getirir, form bu verinin editable snapshot'ını oluşturur. Mutation submit request'ini yönetir ve başarı sonrasında query cache invalidatedilebilir. Query background refetch sonucu kullanıcı dirty formunu sessizce overwrite etmemelidir.
Query Verisini Forma Aktarmak
Query başarılı olduğunda server entity `toFormValues` ile form modeline çevrilebilir. Form ilk kez hydrate edilirken `reset` kullanılabilir. Query yeniden fetch olduğunda dirty form otomatik reset edilmemelidir. Server version değişmişse kullanıcıya conflict veya refresh seçeneği gösterilebilir. Query cache server state'in, React Hook Form ise user draft'ın sahibi olarak kalmalıdır.
Mutation ile Form Göndermek
TanStack Query mutation form submit request'inin loading, error ve success lifecycle'ını yönetebilir. `handleSubmit` valid values'i mutation function'a verir. Mutation function `toApiPayload` ile hazırlanmış API modelini server'a gönderir. React Hook Form `isSubmitting` ile mutation pending state'in ikisini aynı anda kullanmak gerekiyorsa tek source belirlemek gereklidir. Submit button davranışı bütün loading state'leri tutarlı biçimde yansıtmalıdır.
Mutation Error'larını Forma Bağlamak
Mutation error structured API contract içeriyorsa field error'lar `setError` ile form state'e aktarılabilir. Network error veya 500 gibi field'a bağlı olmayan hata root error veya page alert olarak gösterilebilir. Mutation library error object'ini component'ların tek tek parse etmesi yerine ortak mapper kullanılabilir. Retry edilmesi anlamlı error türleri ayrı belirlenmelidir. Error telemetry user-sensitive payload içermemelidir.
Cache Invalidasyonu
Form mutation başarıyla tamamlandığında ilgili detail, list ve summary query'leri stale olabilir. Query key taxonomy doğru tasarlanmışsa yalnız etkilenen cache entry'leri invalidate edilir. Her submit sonrası bütün QueryClient cache'ini temizlemek gereksiz network yükü oluşturur. Server response updated entity döndürüyorsa cache doğrudan güncellenebilir. Invalidation strategy integration test ile doğrulanmalıdır.
Optimistic Update Ne Zaman Kullanılmalı?
Form submit'in sonucu düşük riskli ve kolay geri alınabilir olduğunda optimistic update akıcı deneyim sağlar. Basit preference veya küçük status update buna uygundur. Uzun ve kritik kayıt formunda server sonucu beklemeden success göstermek yanlış güven oluşturabilir. Validation conflict ve permission failure ihtimali yüksek operation'larda normal pending state daha doğru olabilir. Optimistic update kullanıldığında rollback ve server reconciliation test edilmelidir.
Async Validation Nasıl Yönetilir?
Async validation backend bilgisinin gerekli olduğu alanlarda kullanıcıya submit öncesi faydalı feedback sağlar. Ancak her keystroke'ta request göndermek doğru değildir. Debounce ve cancellation aynı alan üzerinde gereksiz veya eski response davranışını azaltır. Async validation sonucu server submit kontrolünün yerine geçmez. Form field state validating durumunu kullanıcıya aşırı dikkat dağıtmadan gösterebilir.
Kullanıcı Adı Kontrolü
Kullanıcı adı uygunluğu server'daki mevcut kayıtlar üzerinden kontrol edilmelidir. Kullanıcı birkaç karakter yazmadan request göndermek gereksiz olabilir. Debounce sonrası endpoint çağrılır ve yalnız en güncel input için sonuç kabul edilir. “Uygun” sonucu submit anına kadar garanti değildir, çünkü başka kullanıcı aynı adı alabilir. Final server mutation unique constraint ve business rule'u yeniden doğrular.
E-posta Benzersizliği
E-posta formatı client schema ile hemen doğrulanabilir. Benzersizlik ise server data gerektirir. Edit formunda kullanıcının mevcut kendi e-posta adresi duplicate sayılmamalıdır. Async endpoint current entity id bilgisini güvenli contract ile dikkate alabilir. Submit sırasında database unique constraint authoritative kontrol olarak kalmalıdır.
Kupon Kodu Kontrolü
Kupon kodu yalnız var mı değil tarih, kullanıcı, ürün ve kullanım limiti gibi kurallara bağlı olabilir. Client async validation kullanıcıya erken feedback verebilir. Server submit veya checkout sırasında kuponu yeniden doğrulamalıdır. Validation sonucunda indirim hesaplaması client'ta gösterilebilir fakat authoritative fiyat server'da hesaplanmalıdır. Expired veya usage limit error code'ları farklı mesajlara map edilebilir.
Vergi Numarası Kontrolü
Vergi numarası formatı local schema ile doğrulanabilir. Harici servis veya kurum sistemi üzerinden gerçek doğrulama gerekiyorsa async request çalıştırılabilir. Dış servis yavaş veya unavailable olabilir, bu nedenle timeout ve fallback policy belirlenmelidir. Kullanıcı formu tamamlayabiliyor mu yoksa doğrulama zorunlu mu business kararıdır. Sensitive identifier log ve analytics payload'ında maskelenmelidir.
Debounce Kullanmak
Debounce input değişikliklerini kısa süre biriktirerek yalnız kullanıcı yazmayı bıraktığında request başlatır. Arama veya uniqueness validation için yaygın modeldir. Süre çok kısa olursa request sayısı yüksek kalır. Çok uzun süre kullanıcı feedback'ini geciktirir. Gerçek typing davranışı ve backend latency göz önünde bulundurularak uygun değer test edilmelidir.
Eski API İsteklerini İptal Etmek
Yeni değer için request başlatıldığında önceki request artık anlamını kaybedebilir. AbortController veya data fetching library cancellation desteği kullanılabilir. Endpoint cancellation desteklemese bile client eski response'u ignore edebilir. Loading state yalnız en güncel request'e bağlanmalıdır. Bu yaklaşım eski response'un yeni field value için yanlış error göstermesini önler.
Async Validation Race Condition'larını Önlemek
Kullanıcı A değerini yazıp request başlattıktan sonra B değerine geçebilir. B request'i önce tamamlanır, ardından A response'u geç gelirse yanlış validation sonucu ekranda görünebilir. Request id veya current value comparison ile yalnız son request sonucu uygulanmalıdır. Query key input değerini içeriyorsa cache identity de daha açık olur. Race condition testinde response sırasını bilinçli ters çevirerek davranış doğrulanmalıdır.
React Hook Form Performans Optimizasyonu
React Hook Form düşük render maliyeti hedeflese de application architecture yanlışsa büyük form yine yavaşlayabilir. Root `watch()`, ağır controlled component'lar ve yüzlerce görünür row performans sorunlarının sık kaynaklarıdır. Subscription'ı field veya section seviyesine çekmek daha etkilidir. Büyük dynamic listelerde virtualization gerekebilir. React DevTools Profiler varsayımları değil gerçek render süresi ve component zincirini göstererek doğru optimizasyon noktasını bulmayı sağlar.
React Hook Form Neden Performanslıdır?
Kütüphane native input ref ve subscription modelinden yararlanarak her değer değişikliğini parent React state üzerinden geçirmek zorunda kalmaz. Form state'in belirli parçaları yalnız kullanan component tarafından izlenebilir. `register` edilen input'lar basit controlled wrapper zinciri oluşturmaz. Bu yaklaşım özellikle çok sayıda field bulunduğunda faydalıdır. Yine de custom UI library bütün input'ları ağır controlled component yapıyorsa performans diğer component davranışlarından etkilenmeye devam eder.
Gereksiz Re-render Neden Oluşur?
Root component'ın bütün form değerlerini watch etmesi en yaygın nedenlerden biridir. Context value kullanımı, parent prop değişimi veya her render'da oluşturulan option listeleri de child component'ları etkileyebilir. Controlled component'lar value değişiminde doğal olarak yeniden render olur. Memoization yalnız gerçekten stabil prop sağlandığında işe yarar. Profiler hangi state değişiminin hangi component'ı tetiklediğini incelemek için kullanılmalıdır.
Global watch() Kullanımından Kaçınmak
Parametresiz `watch()` bütün form değerlerine subscription oluşturur ve root seviyede geniş render davranışı yaratabilir. Debugging sırasında pratik olsa da production UI logic'inde sürekli kullanılması büyük formlarda maliyetlidir. Yalnız gereken field isimleri watch edilebilir. Daha iyi izolasyon için child component içinde `useWatch` tercih edilebilir. Global form summary gibi gerçekten bütün değerleri kullanan nadir component'larda kullanımı yine anlamlı olabilir.
useWatch ile Alan Bazlı Subscription
`useWatch` belirli field veya field grubundaki değişiklikleri hook kullanılan component seviyesinde izler. Conditional section yalnız kontrol field'ını izleyebilir. Bu sayede başka alan değişiklikleri section'ı yeniden render etmek zorunda kalmaz. Nested path ve compute seçenekleri daha hedefli subscription sağlayabilir. Çok fazla ayrı `useWatch` da gereksiz mimari yük oluşturabileceği için gerçek dependency'ler üzerinden kullanılmalıdır.
useFormState ile State İzolasyonu
`useFormState` error, dirty veya submitting gibi meta state'e belirli scope'ta subscribe olmayı sağlar. Root form bütün error object'ini alıp child'lara dağıtmak zorunda kalmaz. Section yalnız kendi field grubunun error durumunu izleyebilir. Reusable input `useController` üzerinden kendi fieldState'ini alabilir. Meta subscription scope'u component ownership ile uyumlu olduğunda render maliyeti azalır.
React.memo Kullanımı
`React.memo` prop'lar değişmediğinde component'ın yeniden render edilmesini engelleyebilir. Ancak form context veya hook subscription component içinde değişiyorsa memo bu update'i durdurmaz. Her row component'a otomatik memo eklemek yerine profiler ile maliyet doğrulanmalıdır. Callback ve object prop'lar her render'da yenileniyorsa memo etkisiz kalabilir. Memoization okunabilirliği bozacak kadar yaygın kullanılmamalıdır.
Büyük Formları Bölümlere Ayırmak
Section component'ları kod ownership ve render sınırı sağlar. Her bölüm yalnız kendi field ve dependency'lerini izleyebilir. Lazy mount bazı nadir alanlarda initial render maliyetini azaltabilir. Wizard zaten doğal section boundary sunar. Bölmek yalnız dosya sayısını artırmak değil state subscription alanını küçültmek için yapılmalıdır.
Yüzlerce Dinamik Satırda Virtualization
Field array yüzlerce row içeriyorsa DOM render maliyeti React Hook Form'dan bağımsız olarak büyür. Virtualization yalnız görünür satırları render eder. Unmount edilen field'ların registration ve `shouldUnregister` davranışı dikkatle test edilmelidir. Keyboard navigation ve screen reader deneyimi de virtualization'dan etkilenebilir. Kullanıcı gerçekten yüzlerce editable row'u aynı anda görmek zorunda mı product tasarımı açısından ayrıca sorgulanmalıdır.
React DevTools Profiler ile Performans Ölçümü
Profiler form interaction sırasında hangi component'ların ne kadar süre render edildiğini gösterir. Tek field yazarken bütün page'in yeniden render olup olmadığı kolayca görülebilir. Before ve after ölçümü optimizasyonun gerçek faydasını doğrular. Development build süreleri production ile aynı değildir, ancak render ilişkisini anlamak için güçlü araçtır. Gerçek kullanıcı cihazlarında INP ve interaction telemetry de production performansını tamamlar.
Dosya Yükleme Alanlarının Yönetimi
Dosya input'ları text field'lardan farklı lifecycle ve güvenlik gereksinimlerine sahiptir. File object browser memory'sinde tutulabilir, ancak localStorage gibi JSON persistence'a uygun değildir. Dosya boyutu ve MIME type client'ta erken kontrol edilebilir fakat server aynı kontrolleri tekrar yapmalıdır. Büyük dosya upload'u ayrı endpoint ve progress tracking isteyebilir. Edit formunda daha önce yüklenen dosya ile yeni seçilen File object aynı modelde açıkça ayrılmalıdır.
File Input ve React Hook Form
Native file input `register` üzerinden form'a bağlanabilir. Browser güvenlik nedeniyle file input value'sunu programatik olarak normal text gibi set etmeye izin vermez. Form data içinde FileList veya seçilen File değerleri ayrı ele alınabilir. Reset davranışı gerçek input element üzerinde test edilmelidir. API multipart/form-data veya pre-signed upload yaklaşımı kullanabilir.
Çoklu Dosya Yükleme
`multiple` file input kullanıcıya birden fazla dosya seçme imkânı verir. Form modeli seçilen yeni dosyalar ile server'da mevcut dosyaları ayrı liste olarak tutabilir. Upload parallel veya sequential yapılabilir. Toplam dosya sayısı ve toplam boyut limiti hem client hem server tarafından kontrol edilmelidir. Başarısız tek dosyanın bütün batch'i etkileyip etkilemeyeceği UX kararına bağlıdır.
Dosya Boyutu ve MIME Type Validation
Client validation kullanıcıya dosya gönderilmeden önce hızlı feedback sağlayabilir. `file.size` ve `file.type` temel kontrol için kullanılabilir. MIME type yalnız client bilgisinden güvenli kabul edilmemeli ve server içerik doğrulaması yapmalıdır. Extension ve MIME ikisi birlikte policy'nin parçası olabilir. Zararlı dosya riski olan sistemlerde malware scanning ayrı server-side süreç gerektirebilir.
Upload Progress
Büyük dosya upload'unda kullanıcı ne kadar ilerlediğini görmek ister. Kullanılan HTTP client veya upload service progress event sağlayabilir. Progress state form field value yerine ayrı upload UI state olarak tutulabilir. Upload tamamlanmadan final form submit'e izin verilip verilmeyeceği açık olmalıdır. Kullanıcı sayfadan ayrılırsa pending upload'un iptal veya devam davranışı belirlenmelidir.
Önceden Yüklenen Dosyaları Edit Formunda Göstermek
Server'da mevcut dosya browser File object olarak yeniden üretilemez. Form modeli mevcut file metadata ve yeni upload değerlerini ayrı alanlarda tutabilir. Kullanıcı mevcut dosyayı indirebilir veya kaldırma için işaretleyebilir. Yeni dosya seçildiğinde replace mi append mi yapılacağı business requirement'tır. `toApiPayload` mevcut, silinen ve yeni dosya durumunu backend'in anlayacağı contract'a dönüştürür.
Dosya Silme ve Form State Senkronizasyonu
Kullanıcı edit formunda mevcut dosyayı kaldırdığında backend kaydı hemen silinmeyebilir. Form `deletedFileIds` benzeri geçici state tutup final submit'te işlemi tamamlayabilir. Immediate delete tercih edilirse undo ve network failure davranışı ayrıca tasarlanmalıdır. Dosya silinmesine rağmen preview listesinde kalmaması gerekir. Server authorization kullanıcının ilgili dosyayı silmeye yetkili olduğunu doğrulamalıdır.
Form Erişilebilirliği (Accessibility)
Erişilebilir form yalnız screen reader kullanıcıları için özel bir sürüm değildir. Semantic input, görünür label, açıklayıcı error ve klavye ile tamamlama bütün kullanıcılar için daha iyi deneyim sağlar. React Hook Form validation state'i accessibility attribute'larına bağlanabilir. Dinamik alan ekleme veya wizard step değişiminde focus yönetimi özellikle önemlidir. Otomatik test araçları yardımcı olsa da gerçek klavye ve screen reader testleri kritik form flow'larında yapılmalıdır.
Semantic Form Elements
Gerçek form için `
`, action için `` ve input için uygun native element kullanılmalıdır. Clickable div üzerine role eklemek yerine native button browser davranışını ücretsiz sağlar. Field group için `fieldset` ve `legend` bazı radio veya checkbox gruplarında güçlü semantic yapı sunar. Submit button type açıkça tanımlanmalıdır. Semantic HTML React Hook Form entegrasyonundan bağımsız olarak erişilebilirliğin temelidir.
Label ve Input İlişkisi
Her input anlaşılır label'a sahip olmalıdır. Label `htmlFor` ile input `id` değerine bağlanabilir. Placeholder kullanıcı yazmaya başladığında kaybolduğu için label yerine kullanılmamalıdır. Complex custom component görünür label ile programatik accessible name sağlamalıdır. Reusable field component bu ilişkiyi bütün projede standardize edebilir.
aria-invalid
Validation hatası bulunan input `aria-invalid="true"` ile işaretlenebilir. Bu bilgi assistive technology'ye alanın geçersiz olduğunu bildirir. Error olmadığı durumda attribute false veya uygun biçimde kaldırılabilir. Yalnız attribute eklemek yeterli değildir, kullanıcıya anlaşılır error mesajı da sunulmalıdır. Field state React Hook Form error bilgisinden doğrudan türetilebilir.
aria-describedby
`aria-describedby` input'u help text veya error message elementine bağlar. Birden fazla açıklama id'si gerektiğinde space-separated biçimde kullanılabilir. Error oluştuğunda ilgili error id ilişkiye eklenebilir. Unique id üretimi reusable component içinde güvenilir olmalıdır. Description metni label'ın tekrarından çok ek yönlendirme sağlamalıdır.
role="alert"
Dinamik error mesajının screen reader tarafından duyurulması için uygun live region veya `role="alert"` kullanılabilir. Her küçük validation değişikliğini agresif biçimde alert etmek kullanıcıyı yorabilir. Submit sonrası ortaya çıkan önemli error için anlamlıdır. Mesaj kısa ve düzeltilebilir olmalıdır. Form-level error summary de uygun announcement davranışı kullanabilir.
İlk Hatalı Alana Focus
Uzun form submit edildiğinde kullanıcı ilk hatanın nerede olduğunu kolayca bulmalıdır. React Hook Form default veya programatik focus davranışıyla error field'a odaklanabilir. Field hidden wizard step'teyse önce ilgili step açılmalıdır. Scroll sırasında sticky header input'u kapatmamalıdır. Focus hareketi kullanıcıya beklenmedik ve sürekli biçimde uygulanmamalıdır.
Dinamik Alan Ekleme/Silmede Screen Reader Bildirimi
Field array'e yeni satır eklendiğinde screen reader kullanıcı değişikliği fark etmeyebilir. Live region kısa biçimde “Yeni satır eklendi” bilgisi verebilir. Focus yeni satırın ilk input'una taşınabilir. Silme işleminde focus mantıklı komşu action'a geri dönmelidir. Sürekli yapılan reorder işleminde gereksiz announcement gürültüsünden kaçınılmalıdır.
Multi-Step Formlarda Erişilebilir Navigasyon
Wizard step başlığı semantic heading olarak sunulmalıdır. Progress indicator mevcut step'i programatik olarak belirtmelidir. Step değiştiğinde focus yeni başlığa veya ilk input'a alınabilir. Back ve next button isimleri yalnız ok ikonuna bırakılmamalıdır. Error bulunan önceki step kullanıcı tarafından kolayca bulunabilmelidir.
Karmaşık React Hook Form Yapıları Nasıl Test Edilir?
Karmaşık form testinde yalnız submit success senaryosunu kontrol etmek yeterli değildir. Validation schema, field array, conditional logic ve server error mapping farklı katmanlarda test edilmelidir. Component testleri kullanıcı etkileşimine odaklanırken schema unit testleri hızlı edge case kontrolü sağlar. E2E test yalnız kritik business journey'leri production'a yakın ortamda doğrular. Testler internal implementation yerine kullanıcının görebildiği davranışı mümkün olduğunca merkezde tutmalıdır.
Validation Schema Unit Testleri
Schema pure input/output davranışı sunduğu için hızlı unit test'e uygundur. Required, boundary ve cross-field kurallar ayrı case'lerde doğrulanabilir. Nested array ve duplicate kontrolü edge case setiyle test edilmelidir. Error path'in doğru field'a bağlandığı kontrol edilebilir. Schema değiştiğinde component render etmeye gerek kalmadan business validation regression'ı yakalanabilir.
Field Component Testleri
Reusable field component label, error ve accessibility davranışıyla test edilmelidir. Input kullanıcı typing'ini kabul ediyor mu ve error state'te `aria-invalid` değişiyor mu kontrol edilir. Implementation class name yerine semantic query kullanmak daha dayanıklı test sağlar. Controlled adapter onChange dönüşümünü doğru yapmalıdır. Bir component library upgrade'i bu testler sayesinde form davranışını sessizce bozmaz.
Form Integration Testleri
Integration test gerçek form component'ı, schema ve mock API davranışını birlikte doğrular. Kullanıcı alanları doldurur, submit eder ve success veya server error görür. Field dependency ve validation timing bu seviyede gerçek kullanıma yakın test edilir. Mock server structured error contract döndürebilir. Test DOM implementation detayına değil kullanıcı aksiyonu ve görünür sonuca odaklanmalıdır.
useFieldArray Testleri
Field array testleri satır identity ve form value değişimini gerçek user action üzerinden doğrular. Append, remove ve reorder operation'ları ayrı senaryolar olabilir. Index değiştiğinde eski input değerlerinin yanlış satıra taşınmadığı kontrol edilmelidir. Validation minimum satır veya duplicate kuralını test edebilir. Row sayısı büyüdüğünde performance e2e veya profiler testi ayrıca gerekebilir.
Alan Ekleme
Kullanıcı “Ekle” butonuna bastığında yeni satır görünmelidir. Yeni input doğru default değerle başlamalıdır. İsteniyorsa focus yeni field'a taşınmalıdır. Submit sonucunda yeni satır payload içinde doğru index ve değerle bulunmalıdır. Maksimum satır sınırı varsa limit sonrası add action kapatılmalıdır.
Alan Silme
Silme action doğru satırı listeden kaldırmalıdır. Başka satırların değerleri aynı kalmalıdır. Minimum satır kuralı ihlal edilmemelidir. Persisted item siliniyorsa delete marker payload davranışı ayrıca test edilebilir. Focus silinen action'dan sonra kullanıcı için anlamlı noktaya taşınmalıdır.
Alan Sıralama
Move veya swap sonrası row değerleri doğru sırada kalmalıdır. React key olarak index kullanılmasıyla oluşabilecek yanlış identity problemi testte kolayca yakalanabilir. Submit payload sıralamayı backend beklentisine göre yansıtmalıdır. Drag-and-drop varsa keyboard alternatifi de test edilmelidir. Reorder sonrasında validation error doğru row ile kalmalıdır.
Conditional Field Testleri
Kontrol field değiştiğinde conditional input görünür veya gizli olmalıdır. Required rule aynı koşula göre çalışmalıdır. Gizlenen alan submit payload'da olmamalıysa bu durum test edilmelidir. Kullanıcı alanı tekrar açtığında eski değerin korunması veya sıfırlanması product kararına göre doğrulanır. Server error hidden field'a gelirse UI'nın nasıl davranacağı edge case olarak düşünülmelidir.
Multi-Step Form Testleri
Kullanıcı geçersiz step ile ileri gidememelidir. Geçerli değerlerle ilerlediğinde önceki step state'i korunmalıdır. Geri dönüş ve tekrar ileri geçiş veri kaybı oluşturmamalıdır. Final submit bütün step schema'sını doğrulamalıdır. Server error önceki step'e aitse kullanıcı doğru adıma yönlendirilmelidir.
API Error Mapping Testleri
Mock API field error, root error ve conflict response üretebilir. Mapper doğru field path için `setError` çağırmalıdır. Unknown error code güvenli genel mesaj üretmelidir. Nested array error path doğru row input'a bağlanmalıdır. Teknik backend mesajı kullanıcıya sızdırılmamalıdır.
Playwright ile E2E Form Testleri
Playwright gerçek browser üzerinden kritik form journey'sini test edebilir. Login, dynamic field, upload ve final submit gibi uçtan uca davranışlar birlikte doğrulanabilir. Her validation rule'u E2E ile test etmek suite'i gereksiz büyütür. En yüksek business risk taşıyan flow'lar seçilmelidir. Network failure veya server conflict belirli testlerde intercept edilerek recovery UX'i de kontrol edilebilir.
React Hook Form'da Sık Yapılan Hatalar
React Hook Form kullanmak form mimarisini otomatik olarak iyi hâle getirmez. Her input için Controller kullanmak, array'de index key seçmek veya root watch ile bütün formu izlemek kütüphanenin performans avantajını azaltabilir. Validation'ın farklı katmanlarda tekrar edilmesi de bakım sorununu sürdürür. API modeli ve form modelini ayırmamak create/edit ekranlarını zorlaştırır. En sağlıklı kullanım library API'sini domain ve state ownership kurallarıyla birlikte düşünmektir.
Her Input İçin Controller Kullanmak
Controller controlled component integration içindir ve native register kullanımının yerine otomatik olarak geçmemelidir. Her text input'u Controller ile sarmak gereksiz render ve boilerplate oluşturabilir. Input `ref`, `name` ve native event sözleşmesine uyuyorsa register daha sade olabilir. Design system component'ı hangi integration modelini desteklediğini açıkça belirtmelidir. Controller gerçek ihtiyaç olduğunda güçlü araçtır, default zorunluluk değildir.
key={index} Kullanmak
Field array'de index key kullanıldığında silme veya reorder sonrası React component identity yanlış eşleşebilir. Kullanıcı bir satıra yazdığı değerin başka row görünümüne taşındığını görebilir. `useFieldArray` stable `field.id` sağlar ve React key olarak bu değer kullanılmalıdır. Index yalnız field path oluşturmak için kullanılabilir. Bu kural dinamik formların en önemli pratiklerinden biridir.
watch() ile Tüm Formu Dinlemek
Parametresiz watch formun tamamına subscription oluşturur. Her input değişikliğinde root component'ın yeniden render olması büyük formda maliyet yaratabilir. Conditional section yalnız ilgili field'ı `useWatch` ile izlemelidir. Debug panel dışında bütün form value'suna sürekli ihtiyaç duyulan senaryo nadirdir. Profiler global watch kullanımının gerçek etkisini kolayca gösterebilir.
Validation Kurallarını Birden Fazla Yerde Tekrarlamak
Aynı min length kuralını input prop, schema ve submit handler içinde üç kez yazmak rule drift üretir. Client schema primary UX rule kaynağı olabilir. Server aynı business requirement'ı güvenlik nedeniyle bağımsız doğrular, fakat frontend içinde tekrar azaltılmalıdır. HTML attribute schema'dan türetilebiliyorsa veya ortak constant kullanılabiliyorsa tutarlılık artar. Tekrar eden metin ve numeric limit shared domain config içinde tutulabilir.
Default Values Tanımlamamak
Default values dirty comparison ve controlled component başlangıcı için önemlidir. Text input undefined başlayıp sonra string olduğunda controlled/uncontrolled warning oluşabilir. Edit ve create form aynı default factory'yi farklı data'yla kullanabilir. Nested object ve array yapıları da güvenli başlangıç shape'ine sahip olmalıdır. Default value davranışı schema nullable ve optional semantics ile uyumlu olmalıdır.
API Verisini Doğrudan Form Modeli Olarak Kullanmak
Backend model çoğu zaman UI input ihtiyaçlarıyla birebir aynı değildir. Null, date, money ve relation alanları form için dönüştürme ister. API object'i doğrudan reset'e vermek component'larda sürekli özel mapping yapılmasına neden olur. `toFormValues` bu dönüşümü tek noktada toplar. Form modeli bağımsız olduğunda backend contract migration'ı UI'yı daha az etkiler.
Gizli Alanların Eski Değerlerini Göndermek
Conditional field gizlenmiş olsa bile kayıtlı değer form state'te kalabilir. Submit payload bütün values'i gönderiyorsa kullanıcı görmediği bilgi backend'e ulaşabilir. `unregister`, setValue veya payload filtering kullanılarak aktif olmayan alanlar temizlenebilir. Hangi alanın korunacağı business requirement'a göre belirlenmelidir. Security-sensitive permission değişiminde hidden değerlerin özellikle kontrol edilmesi gerekir.
Yalnızca Client-Side Validation'a Güvenmek
Client validation atlanabilir. Kullanıcı browser console veya doğrudan HTTP client üzerinden backend request gönderebilir. Server payload, permission ve business constraint'leri tekrar kontrol etmelidir. React Hook Form error UX sağlar, security boundary oluşturmaz. Client ve server validation sorumluluklarının documentation içinde açık ayrılması gerekir.
Server Error'larını Genel Toast Mesajına Dönüştürmek
E-posta alanı duplicate olduğunda yalnız “Bir hata oluştu” toast'ı göstermek kullanıcıya düzeltme yolunu anlatmaz. Structured server field error ilgili input'a map edilmelidir. Form-level hata ise form üstünde görünür olabilir. Toast yalnız global ve geçici notification için kullanılabilir. Error'ın doğru seviyede gösterilmesi form completion süresini önemli ölçüde azaltır.
React Hook Form mu Formik mi TanStack Form mu?
Form library seçimi syntax karşılaştırmasından daha geniş bir karardır. React Hook Form düşük subscription maliyeti, geniş ekosistem ve uncontrolled input yaklaşımıyla uzun süredir güçlü bir seçenektir. Formik birçok mevcut projede kullanılan bilinen bir yapı sunar. TanStack Form güncel v1 dokümantasyonunda first-class TypeScript, headless ve framework-agnostic yaklaşımıyla yeni alternatif oluşturur. Yeni proje seçimi form büyüklüğü, ekip deneyimi, TypeScript beklentisi ve mevcut component sistemi üzerinden yapılmalıdır.
React Hook Form Avantajları
React Hook Form küçük API yüzeyiyle başlayıp dynamic array ve context gibi gelişmiş ihtiyaçlara ölçeklenebilir. Native input'larda register yaklaşımı düşük React state overhead sağlar. Resolver ekosistemi Zod ve Yup dahil birçok schema validator'ı destekler. TypeScript field path type'ları büyük form refactoring'inde değerlidir. Geniş mevcut kullanım ve örnek sayısı ekip onboarding süresini azaltabilir.
Formik Avantajları ve Sınırlamaları
Formik declarative form state modeli ve uzun kullanım geçmişiyle birçok codebase'de tanıdık araçtır. Controlled state yaklaşımı bazı ekipler için anlaşılır ve doğrudan olabilir. Büyük ve sık güncellenen formlarda render behavior dikkatle optimize edilmelidir. Mevcut Formik projesi stabil çalışıyorsa sırf library değiştirmek için migration yapmak gerekli olmayabilir. Yeni projede React Hook Form veya TanStack Form gibi güncel alternatifler gerçek prototiple karşılaştırılabilir.
TanStack Form Yaklaşımı
TanStack Form güncel dokümantasyonunda TypeScript odaklı, headless ve farklı frontend framework'lerine uyarlanabilir form çözümü sunar. Field ve form state subscription yapısı performans hedefi taşır. Async validation için debounce gibi seçenekler API içinde doğrudan desteklenebilir. TanStack ekosistemi kullanan ekipler Query ve diğer araçlarla benzer design yaklaşımından faydalanabilir. Daha yeni adoption profili nedeniyle ekip production deneyimi ve library maturity beklentisini ayrıca değerlendirmelidir.
Performans Karşılaştırması
Performance yalnız library'nin benchmark skoruyla belirlenmez. Formdaki controlled component sayısı, subscription scope, dynamic row miktarı ve custom validation maliyeti gerçek sonucu etkiler. React Hook Form uncontrolled-first yaklaşımıyla büyük native input formlarında güçlü performans sağlar. TanStack Form fine-grained reactive subscription modelini merkezde tutar. Critical form gerçek production component'larıyla prototip edilip profiler üzerinden ölçülmelidir.
TypeScript Desteği
React Hook Form FieldPath ve FieldValues dahil geniş type sistemi sunar. TanStack Form da first-class TypeScript yaklaşımını temel özelliklerinden biri olarak konumlandırır. Formik TypeScript ile kullanılabilir, ancak legacy usage pattern'leri farklı type deneyimi oluşturabilir. Schema validator type inference seçim üzerinde etkili olabilir. TypeScript desteği yalnız generic sayısı değil gerçek field component geliştirirken IDE ve refactoring deneyimi üzerinden değerlendirilmelidir.
Karmaşık Formlarda Hangi Library Seçilmeli?
React Hook Form büyük React codebase için bugün güçlü ve olgun bir varsayılan seçimdir. TanStack Form yeni architecture değerlendiren ekipler için ciddi alternatif olabilir. Mevcut Formik projesi çalışıyorsa migration faydası gerçek performans veya bakım problemiyle gerekçelendirilmelidir. En zor form ekranının küçük proof-of-concept'i library'lerin gerçek component sistemiyle nasıl çalıştığını gösterir. Seçim yapıldıktan sonra organization içinde birkaç farklı form library'nin kontrolsüz biçimde çoğalması önlenmelidir.
React Hook Form İçin JavaScript mi TypeScript mi?
React Hook Form hem JavaScript hem TypeScript ile kullanılabilir. TypeScript zorunlu değildir, ancak nested field path ve büyük API modelleri olan projelerde önemli compile-time güvenlik sağlar. JavaScript küçük proje ve hızlı prototip için yeterlidir. TypeScript özellikle reusable field component ve schema inference kullanımında değerini daha belirgin gösterir. Dil seçimi form library'den bağımsızdır ve ekip codebase standardıyla uyumlu olmalıdır.
React Hook Form Bir Programlama Dili midir?
React Hook Form bir programlama dili değildir. React uygulamalarında form state ve validation yönetimini kolaylaştıran JavaScript kütüphanesidir. JavaScript veya TypeScript proje içinde kullanılabilir. React ve browser form elementleri üzerine abstraction sağlar. Bu ayrım özellikle yeni başlayan geliştiricilerin framework, library ve programlama dili kavramlarını doğru konumlandırması açısından önemlidir.
JavaScript ile Kullanım
JavaScript ile `useForm`, register ve diğer API'ler herhangi bir TypeScript configuration olmadan kullanılabilir. Runtime validation schema yine eklenebilir. Field name yazım hataları compile aşamasında yakalanmadığı için test ve naming discipline daha önemlidir. Küçük uygulamada bu sadelik yeterli olabilir. Proje büyüdükçe TypeScript'e migration form modelindeki hataları daha erken görünür hâle getirebilir.
TypeScript'in Karmaşık Formlardaki Avantajları
TypeScript nested form shape ve field value type'larını açık kontrata dönüştürür. Reusable component yanlış field name veya yanlış value type ile kullanıldığında IDE uyarı verebilir. API payload mapping compile-time kontrol kazanır. Form refactoring sırasında silinen veya adı değişen field kullanımları codebase boyunca bulunur. Bu avantajlar özellikle birden fazla ekip aynı form altyapısını kullandığında değerli hâle gelir.
Type-safe Field Names
`FieldPath` form modelindeki geçerli name değerlerini type düzeyinde sınırlar. Reusable input yalnız var olan path kabul eder. Nested field ve array path'leri refactoring sırasında daha güvenli değiştirilebilir. Dynamic string oluşturma bazı durumlarda type assertion isteyebilir. Assertion kullanımı minimum tutulmalı ve mümkün olduğunda helper type üzerinden doğrulanmalıdır.
API Payload Güvenliği
TypeScript `toApiPayload` fonksiyonunun beklenen request type'ı döndürmesini kontrol edebilir. Form modelinde UI-only field unutulup API payload'a taşınırsa type tasarımına bağlı olarak hata yakalanabilir. Runtime server validation yine zorunludur. Generated API client type'ları backend contract ile frontend arasında ortak sözleşme sağlayabilir. Compile-time type güvenliği development hatalarını azaltır fakat security validation yerine geçmez.
Refactoring Kolaylığı
Field adı veya nested model değiştiğinde TypeScript eski kullanımları işaretler. Form component, schema ve adapter aynı type sisteminden yararlanıyorsa migration alanı daha görünür olur. String tabanlı name kullanımında da FieldPath type bu güvenliği artırır. IDE rename feature birçok referansı otomatik değiştirebilir. Büyük codebase'de bu destek manuel search hatalarını azaltır.
Büyük Projelerde TypeScript Neden Öne Çıkar?
Büyük projede geliştiriciler bütün form modellerini zihinsel olarak hatırlayamaz. TypeScript codebase'in self-documenting contract katmanlarından biri hâline gelir. API, schema, field component ve test fixture aynı type'lardan faydalanabilir. Yeni ekip üyesi IDE autocomplete ile form shape'i daha hızlı keşfeder. TypeScript doğru domain model ve runtime validation'ın yerini tutmaz, ancak değişiklik güvenliğini önemli ölçüde artırır.
React Hook Form ve Open Source İşbirliği
React Hook Form açık kaynak bir proje olduğu için kaynak kodu, issue ve contribution süreçleri topluluk tarafından görülebilir. Resolver ekosistemi farklı schema validator'larla entegrasyon sağlar. Kurumsal ekip açık kaynak package kullanırken yalnız download sayısına bakmamalı, version, release ve security durumunu izlemelidir. Gerekli bug fix upstream'e katkı olarak gönderilebilir. Açık kaynak kullanımı dependency governance sorumluluğunu ortadan kaldırmaz.
React Hook Form'un Açık Kaynak Ekosistemi
React Hook Form GitHub üzerinde açık kaynak olarak geliştirilir ve düzenli release geçmişine sahiptir. Kütüphane çevresinde resolver, UI integration ve community örnekleri oluşmuştur. Kaynak kod erişimi edge case davranışını doğrulamada yardımcı olabilir. Kurumsal ekip dependency'yi fork etmek yerine mümkün olduğunda upstream issue ve pull request üzerinden katkı yapabilir. Kritik production kullanımında version pin ve regression testleri yine kurumun sorumluluğundadır.
Resolver ve Validation Ekosistemi
`@hookform/resolvers` Zod, Yup ve başka birçok validator için ortak integration katmanı sunar. Böylece React Hook Form yalnız tek schema library'ye bağlı kalmaz. Organization kendi validator standardını seçebilir. Resolver upgrade schema library major version değişikliğiyle birlikte test edilmelidir. Custom business validation gerektiğinde her şeyi schema library'ye zorlamak yerine server veya application logic ayrı tutulabilir.
Open Source Form Component'leri
Hazır form component'ları geliştirme hızını artırabilir. Ancak erişilebilirlik, dependency health ve React Hook Form integration modeli incelenmelidir. Component package kendi form state sistemini dayatıyorsa iki farklı source of truth oluşabilir. Code ownership gerekiyorsa source-based component yaklaşımı değerlendirilebilir. Açık kaynak olması design system review ihtiyacını ortadan kaldırmaz.
GitHub Üzerinden Issue ve Pull Request Süreçleri
Bir bug tespit edildiğinde önce minimal reproduction hazırlamak maintainer'ın problemi anlamasını kolaylaştırır. Issue version, browser ve beklenen davranışı açıkça belirtmelidir. Fix geliştirilebiliyorsa test içeren pull request gönderilebilir. Kurumsal fork'ta fix tutmak yerine upstream'e katkı uzun vadeli merge maliyetini azaltabilir. Contribution öncesinde repository guideline ve test komutları takip edilmelidir.
Kurumsal Projelerde Açık Kaynak Bağımlılık Yönetimi
Kurumsal proje form library'nin hangi version'ını kullandığını ve hangi feature'lara bağımlı olduğunu bilmelidir. Lockfile deterministic build için korunmalıdır. Security advisory ve major release notları izlenmelidir. Otomatik dependency update bot'u pull request oluşturabilir, fakat kritik form davranışı testlerden geçmeden merge edilmemelidir. Dependency ownership belirli ekip veya platform sorumluluğuna verilebilir.
Versiyon Kontrolü
Package version range kontrolsüz bırakıldığında farklı environment'larda beklenmeyen dependency değişimleri oluşabilir. Lockfile source control içinde tutulmalıdır. Major upgrade ayrı migration işi olarak değerlendirilmelidir. Form library upgrade'i kritik create/edit ve field array testlerini çalıştırmalıdır. Sürüm kararı yalnız yeni feature isteğine değil security ve maintenance durumuna göre de verilmelidir.
Dependency Security
Dependency scanner bilinen vulnerability'leri takip edebilir. Form library küçük görünse de resolver veya UI integration transitive dependency getirebilir. Yeni package eklemeden önce maintenance ve security geçmişi incelenmelidir. Security advisory çıktığında exploitability gerçek kullanım üzerinden değerlendirilmelidir. Güncelleme mümkün değilse temporary mitigation ve upgrade planı hazırlanmalıdır.
Breaking Change Yönetimi
Major release API ve behavior değişikliği getirebilir. Migration guide ve changelog okunmalıdır. Birkaç kritik form staging environment'ta manuel ve otomatik test edilmelidir. Custom wrapper API kullanmak library değişikliklerinin feature code'a yayılmasını azaltabilir. Upgrade tek dev pull request'te bütün codebase'i değiştirmek yerine gerektiğinde kademeli yürütülebilir.
Üretim Ortamında React Hook Form İçin Kontrol Listesi
Form production'a çıkmadan yalnız happy path submit'in çalışması yeterli değildir. Type safety, client ve server validation, error mapping, accessibility ve performance birlikte kontrol edilmelidir. Autosave veya draft varsa race condition ve migration senaryoları test edilmelidir. Monitoring kullanıcıların hangi form adımında hata yaşadığını gösterebilir. Kontrol listesi ekiplerin her yeni formda aynı kalite standardını tekrar uygulamasını sağlar.
Type Safety
Form values, field names ve API adapter TypeScript kullanılıyorsa mümkün olduğunca gerçek type'larla tanımlanmalıdır. `any` kritik form modelinde kolay kaçış yolu olmamalıdır. Schema output ve form input type farkı açık tutulmalıdır. Generated API type varsa adapter onunla uyumlu olmalıdır. Typecheck CI pipeline'ın zorunlu parçası olmalıdır.
Client Validation
Kullanıcı required ve format hatalarını submit öncesinde görebilmelidir. Validation message product diliyle açık yazılmalıdır. Cross-field ve conditional rule'lar test edilmelidir. Validation mode form boyutuna ve UX'e göre seçilmelidir. Client validation server kontrolünün yerine geçmemelidir.
Server Validation
Backend bütün payload ve permission kurallarını yeniden doğrulamalıdır. Database unique ve concurrency kuralı burada uygulanır. Validation failure structured error contract ile dönmelidir. Sensitive internal exception kullanıcıya expose edilmemelidir. Server testleri client olmadan doğrudan endpoint veya action seviyesinde çalışmalıdır.
Error Mapping
Field error ilgili input üzerinde görünmelidir. Root error form genelinde anlaşılır mesaj üretmelidir. Unknown backend code güvenli fallback'e dönüşmelidir. Nested field array path mapping test edilmelidir. Error translation merkezi helper üzerinden standardize edilebilir.
Accessibility
Form keyboard ile tamamlanabilmelidir. Label, error description ve focus state doğru olmalıdır. Submit sonrası ilk hata kullanıcı tarafından kolay bulunmalıdır. Dynamic field ekleme ve wizard navigation screen reader ile test edilmelidir. Automated accessibility scan CI quality gate'e eklenebilir.
Performance
Root watch veya geniş formState subscription bulunup bulunmadığı kontrol edilmelidir. Dynamic row sayısı production büyüklüğünde test edilmelidir. Heavy editor ve date picker bundle etkisi ölçülmelidir. Profiler gereksiz render zincirini göstermelidir. Performance optimization gerçek metric ile doğrulanmalıdır.
Autosave ve Draft
Draft feature kullanılıyorsa hangi field'ların saklandığı açık olmalıdır. Sensitive data persistence dışında tutulmalıdır. Debounce ve request ordering test edilmelidir. Server conflict durumunda veri sessizce ezilmemelidir. Draft schema version migration planı bulunmalıdır.
Test Coverage
Coverage yüzdesi tek kalite metriği değildir. Schema edge case, field array ve critical submit flow test edilmelidir. Server error mapping regression test almalıdır. E2E yalnız yüksek riskli journey'leri kapsamalıdır. Test suite hızlı feedback verecek şekilde katmanlandırılmalıdır.
Analytics ve Monitoring
Form start, submit success ve önemli error oranları product analytics'te ölçülebilir. Field value gibi hassas kullanıcı verisi analytics'e gönderilmemelidir. Validation error code aggregate metric olarak kullanılabilir. Mutation latency ve server failure monitoring ayrı takip edilmelidir. Kullanıcıların belirli step'te sürekli takılması ürün iyileştirmesi için değerli sinyal sağlar.
Sıkça Sorulan Sorular
React Hook Form hakkında soruların önemli bölümü performans, dynamic field, schema validation ve alternatif library seçimi etrafında toplanır. Doğru cevap yalnız library API'sine değil formun veri ve kullanıcı akışına bağlıdır. Basit formda küçük çözüm yeterliyken kurumsal wizard daha açık schema, API adapter ve test katmanı ister. React Hook Form güçlü bir araçtır, ancak server validation ve accessibility gibi sorumlulukları otomatik olarak çözmez. Aşağıdaki cevaplar karar verirken en sık karşılaşılan noktaları pratik biçimde özetler.
React Hook Form nedir?
React Hook Form, React uygulamalarında form state ve validation yönetimi için kullanılan açık kaynak bir kütüphanedir. Native input registration ve subscription yaklaşımıyla gereksiz React render'larını azaltmayı hedefler. Dynamic array, controlled component ve schema resolver entegrasyonu gibi gelişmiş ihtiyaçları destekler. TypeScript ile field path ve form modelinde güçlü type desteği sunar. Küçük formdan büyük kurumsal form altyapısına kadar farklı ölçekte kullanılabilir.
React Hook Form büyük formlar için uygun mudur?
Evet, doğru component ve subscription mimarisiyle büyük formlar için uygundur. Form section'lara ayrılmalı ve root seviyede bütün values sürekli izlenmemelidir. Dynamic array için `useFieldArray`, meta state için `useFormState` ve field bazlı takip için `useWatch` kullanılabilir. Çok büyük visible row sayısında virtualization gerekebilir. Performance gerçek form component'larıyla profiler üzerinden doğrulanmalıdır.
useFieldArray ne işe yarar?
`useFieldArray` dinamik array field'larını ekleme, silme ve sıralama işlemleriyle yönetir. `fields` listesi her row için stable `id` sağlar. Append, remove, move ve replace gibi method'lar form state ile birlikte çalışır. React key olarak `field.id` kullanılmalıdır. Array-level schema validation minimum satır ve duplicate gibi kuralları tamamlayabilir.
React Hook Form ile dinamik form nasıl oluşturulur?
Dinamik array için `useFieldArray`, conditional field için `useWatch` kullanılabilir. Her yeni field uygun default değerle register edilir. Gizlenen field'ın form state'te kalıp kalmayacağı business gereksinimine göre belirlenir. Schema dynamic yapının tamamını doğrulamalıdır. API payload dönüşümü active ve silinen field'ları doğru biçimde ele almalıdır.
React Hook Form ile Zod nasıl kullanılır?
Zod schema oluşturulup `zodResolver` `useForm` resolver seçeneğine verilebilir. Schema required, nested ve cross-field kuralları tanımlar. TypeScript form type'ı schema'dan türetilebilir. Resolver validation error'larını React Hook Form error modeline dönüştürür. Server aynı veya daha güçlü validation'ı tekrar çalıştırmalıdır.
Zod mu Yup mı tercih edilmeli?
Yeni TypeScript ağırlıklı projede Zod güçlü type inference nedeniyle avantajlı olabilir. Mevcut Yup schema yatırımı olan projede migration zorunlu değildir. İki araç da React Hook Form resolver ekosistemi tarafından desteklenir. Ekip deneyimi ve server-side reuse ihtiyacı kararın parçasıdır. Tek organization içinde mümkün olduğunca ortak schema standardı kullanmak bakım kolaylığı sağlar.
Controller ne zaman kullanılmalı?
Native `register` contract'ına uymayan controlled UI component'larda Controller kullanılmalıdır. Date picker, özel Select ve rich editor sık örneklerdir. Basit native input'ta register daha sade olabilir. Controller field value ve event mapping için adapter görevi görür. Design system wrapper aynı integration davranışını bütün feature'lar için standardize edebilir.
watch ile useWatch arasındaki fark nedir?
`watch` form değerlerini form instance seviyesinde takip eder. Bütün formu watch etmek root component'ta geniş re-render davranışı oluşturabilir. `useWatch` subscription'ı hook kullanılan component seviyesinde izole etmeye yardımcı olur. Büyük formlarda conditional UI için `useWatch` çoğu zaman daha uygun olur. Yalnız gerekli field'ı izlemek performans ve code clarity açısından daha iyi sonuç verir.
Çok adımlı formda tek useForm yeterli midir?
Adımlar tek business payload oluşturuyorsa tek `useForm` çoğu zaman yeterlidir. Step component'ları FormProvider üzerinden aynı state'i paylaşabilir. `trigger` ile step-specific validation çalıştırılabilir. Route bazlı bağımsız kayıt akışlarında her step için ayrı form tercih edilebilir. Karar data lifecycle ve save semantics üzerinden verilmelidir.
API validation hataları React Hook Form'a nasıl aktarılır?
Backend structured field error ve form-level error contract döndürmelidir. Field path'ler `setError` ile ilgili input'a bağlanabilir. Genel conflict veya network error root seviyesinde gösterilebilir. Machine-readable error code localization ve farklı UI davranışını kolaylaştırır. Teknik database exception kullanıcıya doğrudan gösterilmemelidir.
React Hook Form performansı nasıl optimize edilir?
Root seviyede bütün formu `watch()` ile izlemekten kaçınılmalıdır. `useWatch`, `useFormState` ve `useController` subscription'ı ilgili component'a yaklaştırabilir. Büyük field array row component'ları ayrılabilir. Gerektiğinde virtualization ve lazy loading kullanılabilir. React DevTools Profiler gerçek render bottleneck'ini belirlemek için kullanılmalıdır.
React Hook Form TypeScript ile kullanılmalı mı?
Zorunlu değildir, ancak büyük projede önemli avantaj sağlar. FieldPath type-safe name, API adapter ve schema inference refactoring güvenliğini artırır. Reusable component generic type ile yanlış field kullanımını engelleyebilir. Runtime server validation yine gereklidir. Kurumsal codebase TypeScript kullanıyorsa React Hook Form da aynı type modelinden faydalanmalıdır.
Formik'ten React Hook Form'a geçmek mantıklı mı?
Mevcut Formik uygulaması stabil, hızlı ve kolay bakım yapılıyorsa yalnız trend nedeniyle migration gerekli değildir. Büyük formlarda render problemi, tekrar eden form code'u veya yeni component architecture ihtiyacı varsa React Hook Form değerlendirilabilir. Migration bir form veya feature üzerinde pilot olarak yapılmalıdır. Consumer API ve validation schema mümkün olduğunca korunabilir. Gerçek geliştirme süresi, bundle ve performance farkı ölçülerek migration kararı verilmelidir.
Karmaşık Form Yönetimi ve React Hook Form Entegrasyonu konusunda sürdürülebilir sonuç almak için asıl hedef mümkün olduğunca fazla hook kullanmak değil, formun veri sahipliğini ve katmanlarını doğru kurmaktır. Schema, React Hook Form state'i, UI state, server state ve API mapping birbirinden ayrıldığında hem performans hem test edilebilirlik belirgin biçimde iyileşir. Dinamik array, wizard, autosave ve server validation gibi ileri ihtiyaçlar aynı temel mimari üzerinde kontrollü biçimde büyütülebilir. Kurumsal frontend mimarisi, TypeScript, React ve sürdürülebilir form geliştirme üzerine diğer çalışmaları incelemek için https://www.diyarbakiryazilim.com.tr adresini ziyaret edebilirsiniz. Proje örnekleri için https://www.diyarbakiryazilim.com.tr/projects ve topluluk hakkında bilgi için https://www.diyarbakiryazilim.com.tr/about adresleri kullanılabilir.
share: