Karakterizasyon testleri, küçük güvenli adımlar ve durum ayırma ile Claude Code kullanarak React bileşenlerini davranışı değiştirmeden nasıl yapılandıracağınızı öğrenin.

React refaktörleri riskli hissettirir çünkü çoğu bileşen küçük, temiz yapı taşları değildir. UI, state, effect'ler ve “bir prop daha ekleyeyim” düzeltmeleriyle yaşayan karışık yapılardır. Yapıyı değiştirdiğinizde çoğunlukla zamanlama, kimlik ya da veri akışını istemeden değiştirirsiniz.
Bir refaktör en sık şu durumlarda davranışı değiştirir:
key değiştiği için state'in sıfırlanması.Refaktörler aynı zamanda “temizleme” ile “iyileştirme” karıştığında yeniden yazımlara döner. Bir bileşen çıkarmayla başlarsınız, sonra bir sürü şeyi yeniden adlandırırsınız, sonra state yapısını “düzeltirsiniz”, sonra bir hook’u değiştirirsiniz. Kısa sürede hem mantığı hem de layout'u değiştirmiş olursunuz. Koruyucu önlemler yoksa hangi değişikliğin hataya yol açtığını anlamak zordur.
Güvenli bir refaktörün bir vaadi vardır: kullanıcılar aynı davranışı görür ve ortaya daha anlaşılır kod çıkar. Prop'lar, event'ler, yükleme durumları, hata durumları ve kenar durumları aynı şekilde davranmalı. Eğer davranış değişiyorsa, bu kasıtlı, küçük ve açıkça belirtilmiş olmalıdır.
Claude Code (veya herhangi bir kod yardımcısı) ile React bileşenlerini refaktörlüyorsanız, onu otomatik pilot değil hızlı bir eş programcı gibi ele alın. Düzenleme yapmadan önce riskleri açıklamasını isteyin, küçük adımlardan oluşan bir plan önerisini isteyin ve davranışın aynı kaldığını nasıl kontrol ettiğini açıklamasını isteyin. Sonra kendiniz doğrulayın: uygulamayı çalıştırın, garip yolları tıklayın ve bileşenin bugün ne yaptığını yakalayan testlere güvenin, ideal davranışı değil.
Zamanınızı aktif olarak çalan tek bir bileşen seçin. Tüm sayfa değil, “UI katmanı” değil ve belirsiz bir “temizlik” de değil. Okuması zor, değiştirmesi zor veya kırılgan state ve yan etkilerle dolu tek bir bileşen seçin. Dar bir hedef, asistan önerilerini doğrulamayı da kolaylaştırır.
Beş dakikada kontrol edebileceğiniz bir hedef yazın. İyi hedefler yapı üzerinedir, sonuç değil: “daha küçük bileşenlere ayır”, “state’i takip etmeyi kolaylaştır”, veya “uygulamanın yarısını mocklamadan test edilebilir yap”. “Daha iyi yap” veya “performansı artır” gibi hedeflerden kaçının; bir metriğiniz ve bilinen bir darboğazınız yoksa.
Düzenleyiciyi açmadan önce sınırları belirleyin. En güvenli refaktörler sıkıcıdır:
Sonra kodu taşırken davranışı sessizce bozabilecek bağımlılıkları listeleyin: API çağrıları, context provider'ları, routing parametreleri, feature flag'ler, analitik event'leri ve paylaşılan global state.
Somut bir örnek: 600 satırlık bir OrdersTable var ve veri çekiyor, filtreliyor, seçim yönetiyor ve detaylar için bir drawer gösteriyor. Net bir hedef olabilir: “satır render'ını ve drawer UI'ını bileşenlere çıkar, seçim state'ini tek bir reducer'a taşı, UI değişikliği yok.” Bu hedef, “bitti”nin ne olduğunu ve kapsam dışında olanı söyler.
Refaktöre başlamadan önce bileşeni siyah kutu gibi ele alın. Göreviniz bileşenin bugün ne yaptığını yakalamaktır, uzun vadede ne yapmasını istediğiniz değil. Bu, refaktörün yeniden tasarıma dönmesini engeller.
Önce mevcut davranışı düz anlatımla yazın: bu girdiler verildiğinde UI şu çıktıyı gösterir. Props, URL parametreleri, feature flag'ler ve context ya da store'dan gelen verileri dahil edin. Claude Code kullanıyorsanız, küçük ve odaklı bir snippet yapıştırıp davranışı daha sonra kontrol edebileceğiniz kesin cümlelerle tekrar ifade etmesini isteyin.
Kullanıcıların gerçekten gördüğü UI durumlarını kapsayın. Bir bileşen mutlu yolunda iyi görünürken, yükleme, boş veya hata durumunda kırılabilir.
Ayrıca gözden kaçması kolay, refaktörlerde davranışı bozan örtük kuralları yakalayın:
Örnek: bir kullanıcı tablosu var; sonuçları yüklüyor, arama destekliyor ve “Son aktif”e göre sıralıyor. Arama boşken ne olur, API boş liste döndüğünde ne olur, API hata verdiğinde ne olur ve iki kullanıcının aynı “Son aktif” zamanına sahip olduğu durumda ne olur gibi durumları yazın. Küçük ayrıntılar (sıralama büyük/küçük harf duyarsız mı, filtre değiştiğinde tablo sayfasını koruyor mu) gibi şeyleri not edin.
Notlar sıkıcı ve spesifik hissettikçe hazır hale gelirsiniz.
Karakterizasyon testleri, “bugün böyle yapıyor” testleridir. Hatta tuhaf veya tutarsız olsa bile mevcut davranışı tanımlarlar. Tuhaf gelebilir ama bu testler refaktörün gizlice yeniden yazılmasını engeller.
React bileşenlerini Claude Code ile refaktörlüyorsanız, bu testler güvenlik raylarınızdır. Araç kodu şekillendirmede yardımcı olabilir ama hangi davranışın değişmemesi gerektiğine siz karar verirsiniz.
Kullanıcıların (ve diğer kodun) dayandığı şeylere odaklanın:
Testlerin stabil kalması için sonucu iddia edin, implementasyonu değil. “Kaydet butonu devre dışı kalır ve bir mesaj görünür” demek, “setState çağrıldı” demekten iyidir. Bir test bileşenin adını değiştirmek veya hook'ları yeniden sıralamak yüzünden kırılıyorsa davranışı korumuyordu.
Asenkron davranış refaktörlerin sık değiştirdiği zamandır. Bunu açıkça ele alın: UI'nın yerleşmesini bekleyin, sonra iddia edin. Zamanlayıcılar (debounced search, geciktirilmiş toast'lar) varsa fake timer kullanın ve zamanı ilerletin. Ağ çağrıları varsa fetch'i mocklayın ve başarı ile hatadan sonra kullanıcıya görüneni doğrulayın. Suspense benzeri akışlar için hem fallback hem de çözülen görünümü test edin.
Örnek: bir “Users” tablosu, arama tamamlandıktan sonra sadece “Sonuç yok” gösterir. Bir karakterizasyon testi bu sıralamayı kilitlemeli: önce loading göstergesi, sonra satırlar ya da boş mesaj, bileşeni daha sonra nasıl bölerseniz bölün.
Kazanç “daha büyük değişiklikler daha hızlı” değildir. Kazanç, bileşenin ne yaptığını net görmek ve davranışı sabit tutarak tek seferde küçük değişiklikler yapmaktır.
Önce bileşeni yapıştırın ve sorumluluklarının düz İngilizce (ya da sizin dilinizde) bir özetini isteyin. Spesifik olun: hangi verileri gösteriyor, hangi kullanıcı işlemlerini ele alıyor ve hangi yan etkileri tetikliyor (fetch, timer, abonelik, analitik). Bu genellikle refaktörleri riskli yapan gizli işleri ortaya çıkarır.
Sonra bir bağımlılık haritası isteyin. Her girdi ve çıktının envanterini istiyorsunuz: prop'lar, context okumaları, custom hook'lar, local state, türetilen değerler, effect'ler ve modül-seviyesindeki yardımcılar. Faydalı bir harita ayrıca taşınmasının güvenli olduğu (saf hesaplamalar) ile “yapışkan” olanları (zamanlama, DOM, ağ) da belirtir.
Sonra çıkarma adayları önerisini isteyin, tek katı kural: saf view parçalarını stateful controller parçalarından ayır. Sadece prop alan ve JSX içeren kısımlar ilk extractions için iyidir. Olay işleyiciler, asenkron çağrılar ve state güncellemelerini karıştıran bölümler genellikle değildir.
Güçlü tutan bir iş akışı:
Kontrol noktaları önemlidir. Claude Code'dan her adımın commit edilebilir ve geri alınabilir olduğu minimal bir plan isteyin. Pratik bir checkpoint: “\u003cTableHeader\u003e'ı mantık değiştirmeden çıkar” gibi bir hedef, sıralamayı ellememek için iyi bir örnektir.
Somut örnek: bir bileşen müşteri tablosu render ediyor, filtreleri kontrol ediyor ve veriyi çekiyorsa önce tablo markup'ını (header, satırlar, empty state) saf bir bileşene çıkarın. Ondan sonra filtre state'ini veya fetch effect'ini taşımaya geçin. Bu sıra, JSX ile birlikte gezen hataların yayılmasını engeller.
Büyük bir bileşeni böldüğünüzde asıl risk JSX'i taşımak değildir; asıl risk veri akışı, zamanlama veya event kablajının istemeden değişmesidir. Çıkarma işlemini önce kopyala-ve-bağla olarak yapın, sonra temizlemeyi ayrı adımda yapın.
Başlamak için UI içinde zaten var olan sınırları arayın, dosya yapısında değil. Bir cümleyle kendi “şeyi” olarak tanımlayabileceğiniz bölümler arayın: butonlu bir header, filtre çubuğu, sonuç listesi, sayfalama footer'ı.
Güvenli ilk hamle saf sunumsal bileşenleri çıkarmaktır: prop alır, JSX verir. Kasıtlı olarak sıkıcı bırakın. Yeni state, yeni effect veya yeni API çağrısı eklemeyin. Orijinal bileşende bir tıklama handler'ı üç şey yapıyorduysa, handler'ı ebeveynde tutun ve aşağıya props olarak gönderin.
Genellikle işe yarayan sınırlar: başlık alanı, liste ve satır öğesi, sadece input içeren filtreler, footer kontrolleri (sayfalama, toplamlar, toplu işlemler) ve dialog'lar (açma/kapatma ve callback'ler props ile verilir).
İsimlendirme insanların düşündüğünden daha çok önemlidir. UsersTableHeader veya InvoiceRowActions gibi spesifik isimler seçin. “Utils” veya “HelperComponent” gibi toplama isimlerinden kaçının; sorumlulukları gizler ve ilgisiz işleri karıştırmaya davetiye çıkarır.
Gerçek bir ihtiyaç olmadıkça bir container bileşeni tanıtmayın: UI'nın bir kısmı state veya effect sahibi olmak zorunda kaldığında container gerekir. Yine de dar tutun. İyi bir container tek bir amaca sahip olur (ör. “filter state”) ve diğer her şeyi prop olarak aktarır.
Karışık bileşenler genellikle üç tür veriyi karıştırır: gerçek UI state'i (kullanıcının değiştirdiği), türetilmiş veri (hesaplanabilir olan), ve sunucu state'i (ağdan gelen). Hepsini local state gibi ele alırsanız refaktörler riskli olur çünkü güncellemelerin ne zaman olacağını kazara değiştirebilirsiniz.
Önce her veri parçasını etiketleyin. Soru sorun: kullanıcı mu bunu düzenliyor, yoksa prop/state ve çekilen veriden hesaplanabilir mi? Ayrıca sorun: bu değer burada mı sahipleniliyor yoksa sadece geçirilmiş mi?
Türetilen değerler useState içinde olmamalı. Küçük bir fonksiyona veya pahalıysa memoize edilmiş bir selector'a taşıyın. Bu state güncellemelerini azaltır ve davranışı öngörülebilir kılar.
Güvenli bir desen:
useState'te tutun.useMemo ile sarın.Effect'ler çok fazla şey yaptığında veya yanlış bağımlılıklara tepki verdiğinde davranışı bozar. Her amaç için bir effect hedefleyin: bir effect localStorage ile senkronize etmek için, bir effect fetch için, bir effect abonelikler için. Bir effect çok sayıda değer okuyorsa genellikle ekstra sorumlulukları gizliyordur.
Claude Code kullanıyorsanız küçük bir değişiklik isteyin: bir effect'i ikiye böl veya bir sorumluluğu bir yardımcıya taşı. Sonra her taşımadan sonra karakterizasyon testlerini çalıştırın.
Prop drilling konusunda dikkatli olun. Bunu context ile değiştirmek yalnızca tekrar eden kabloyu kaldırıp sahipliği netleştirdiğinde fayda sağlar. İyi bir işaret, context'in app-seviyesinde bir kavram gibi okunmasıdır (mevcut kullanıcı, tema, feature flag'ler), tek bir bileşen ağacı için geçici bir çözüm olmamalıdır.
Örnek: bir tablo bileşeni hem rows hem de filteredRows state'inde tutuyor olabilir. rows state olarak kalmalı, filteredRows ise rows + query'den hesaplanmalı ve filtreleme kodu saf bir fonksiyonda tutulmalı ki test edilmesi kolay ve kırılması zor olsun.
Refaktörler en çok çok fazla değişiklik yapıp fark etmeden ilerlediğinizde ters gider. Çözüm basit: küçük checkpoint'lerde çalışın ve her checkpoint'i mini bir sürüm gibi ele alın. Aynı dalda çalışıyor olsanız bile değişikliklerinizi PR boyutunda tutun ki neyin kırıldığını ve nedenini görebilin.
Her anlamlı hamleden sonra durup davranışın değişmediğini kanıtlayın. Bu kanıt otomatik olabilir (testler) veya manuel (tarayıcıda hızlı bir kontrol). Amaç mükemmellik değil; hızlı tespit.
Pratik bir checkpoint döngüsü:
Koder.ai gibi bir platform kullanıyorsanız snapshot'lar ve rollback, iterasyon sırasında güvenlik rayı gibi davranabilir. Normal commit'leriniz olsun ama snapshot'lar “bilinen iyi” bir sürümle karşılaştırma veya deneme yanlış gittiğinde geri dönme konusunda yardımcı olur.
Giderken basit bir davranış defteri tutun. Bu sadece neyi doğruladığınıza dair kısa bir nottur ve aynı şeyleri tekrar tekrar kontrol etmenizi engeller.
Örnek:
Bir şey kırıldığında defter size neyi yeniden kontrol etmeniz gerektiğini söyler ve checkpoint'ler geri dönmeyi ucuzlatır.
Çoğu refaktör küçük, sıkıcı şekillerde başarısız olur. UI çalışıyor gibi görünür ama bir boşluk kuralı kaybolur, bir tıklama iki kez tetiklenir veya bir liste yazarken odak kaybeder. Asistanlar kodu daha temiz gösterdiği için bu daha zor farkedilir.
Yapıyı değiştirmek en yaygın sebeptir. Bir bileşeni çıkarırsınız ve fazladan bir \u003cdiv\u003e sararsınız veya \u003cbutton\u003e yerine tıklanabilir \u003cdiv\u003e kullanırsınız. Bu, CSS seçicilerini, düzeni, klavye navigasyonunu ve test sorgularını değiştirebilir.
En sık davranışı bozan tuzaklar:
{} veya () => {}) ekstra re-render'lara ve child state'in sıfırlanmasına neden olabilir. Eskiden stabil olan prop'lara dikkat edin.useEffect, useMemo veya useCallback içine taşımak, bağımlılıklar değişirse stale değerler veya döngüler yaratabilir. Bir effect eskiden “click'te” çalışıyorduysa, onu “her şey değiştiğinde” çalışır hale getirmeyin.Somut örnek: bir tablo bileşenini bölerken satır anahtarlarını ID yerine dizi indeksiyle değiştirmek iyi görünse de, sıralama olduğunda seçim state'inin bozulmasına neden olabilir. “Temiz” olmak bir bonus olsun; “aynı davranış” gereklilik olsun.
Merge etmeden önce refaktörün davranışı koruduğuna dair kanıt istersiniz. En kolay gösterge sıkıcıdır: testler hala çalışıyor ve siz testleri “düzeltmek” zorunda kalmıyorsunuz.
Son küçük değişiklikten sonra bu hızlı geçişi yapın:
onChange kullanıcı girdisinde çalışıyor, mount'ta değil).Hızlı bir akıl sağlığı kontrolü: bileşeni açın ve garip bir akışı deneyin, mesela bir hatayı tetikleyin, tekrar deneyin, sonra filtreleri temizleyin. Refaktörler genellikle ana yol çalışırken geçişleri bozar.
Herhangi bir madde başarısız olursa son değişikliği geri alın ve daha küçük bir adımla yeniden deneyin. Büyük diff'i debug etmekten genellikle daha hızlıdır.
Bir ProductTable hayal edin: veri çekiyor, filtreleri yönetiyor, sayfalama kontrol ediyor, silme için onay diyaloğu açıyor ve satır eylemleri (düzenle, kopyala, arşivle) ile uğraşıyor. Küçükken başlamış, sonra 900 satırlık bir dosyaya dönüşmüş.
Belirtiler tanıdık: state useState çağrıları arasında dağılmış, birkaç useEffect belirli bir sıra ile çalışıyor ve bir “zararsız” değişiklik sadece bir filtre aktifken sayfalamayı kırıyor. İnsanlar dokunmamayı tercih ediyor çünkü öngörülemez hissediyor.
Yapıyı değiştirmeden önce birkaç React karakterizasyon testi ile davranışı kilitleyin. Kullanıcıların yaptıklarına odaklanın, iç state'e değil:
Şimdi küçük commit'lerde refaktör yapabilirsiniz. Temiz bir çıkarma planı şöyle olabilir: FilterBar kontrolleri render eder ve filtre değişikliklerini iletir; TableView satırları ve sayfalamayı render eder; RowActions action menüsü ve onay dialog UI'sını tutar; ve useProductTable hook'u karışık mantığı (query param, türetilmiş state ve yan etkiler) sahiplenir.
Sıra önemlidir. Önce saf UI'yi çıkarın (TableView, FilterBar) ve prop'ları değişmeden geçirerek. Riskli kısmı sona bırakın: state ve effect'leri useProductTable içine taşımak. Taşırken eski prop isimlerini ve event şekillerini koruyun ki testler yeşil kalsın. Bir test kırılırsa bir stil değil davranış değiştiğini bulmuşsunuz demektir.
Claude Code ile React bileşenlerini güvenli hissettiren bir hal almak istiyorsanız yaptıklarınızı küçük bir şablona dönüştürün. Amaç daha fazla süreç değil; daha az sürprizdir.
Her bileşende, yorgun veya acele halindeyken bile takip edebileceğiniz kısa bir playbook yazın:
Bunu notlarınızda veya repo'da snippet olarak saklayın ki sonraki refaktör aynı güvenlik raylarıyla başlasın.
Bileşen sabit ve daha okunaklı olduğunda, kullanıcı etkisine göre bir sonraki adımı seçin. Yaygın bir sıra: önce erişilebilirlik (label'lar, odak, klavye), sonra performans (memoization, pahalı render'lar), sonra temizlik (tipler, isimlendirme, ölü kod). Üçünü bir PR'da karıştırmayın.
Koder.ai gibi vibe-coding iş akışları kullanıyorsanız, planlama modu adımları düzenlemenize yardımcı olur ve snapshot/rollback checkpoint'ler olarak iş görür. Bitince kaynak kodunu dışa aktarmak son diffları incelemeyi ve temiz geçmiş tutmayı kolaylaştırır.
Testler, kırılmasını korktuğunuz davranışları kapsadığında, bir sonraki değişiklik yeni bir özellik olurdu veya “mükemmelleştirme” dürtüsü geldiğinde durun ve gönderin. Eğer büyük formu bölmek karmaşık state'i çözdüyse ve testler validasyon ve submit yollarını kapsıyorsa, gönderin. Kalan fikirleri kısa bir backlog olarak saklayın.
React refaktörleri sıklıkla kimliği ve zamanlamayı fark etmeden değiştirir. Yaygın davranış bozulmaları şunlardır:
key değiştiği için state'in sıfırlanması.Yapısal bir değişikliğin, testler kanıtlayana dek davranış değişikliği olabileceğini varsayın.
Yapı odaklı, kısa ve kontrol edilebilir bir hedef belirleyin; sonuç odaklı değil. İyi bir hedef şu şekilde olur:
“Daha iyi yap” gibi belirsiz hedeflerden kaçının; elinizde ölçü ve bilinen bir darboğaz yoksa performans iddiaları koymayın.
Bileşeni karanlık bir kutu gibi ele alıp kullanıcıların gözlemleyebildiği davranışı yazın:
Notlar sıkıcı ve spesifik hissettikçe kullanışlıdır.
Karakterizasyon testleri ekleyin: bileşenin bugünkü davranışını tanımlayan testler, garip veya tutarsız olanı bile. Praktik hedefler:
Testlerde uygulama çıktısını iddia edin, iç implementasyonu değil.
Asistanı dikkatli bir eş programcı gibi kullanın:
Büyük bir “yeniden yazma” diff'ini kabul etmeyin; doğrulanabilir küçük değişiklikler talep edin.
Önce saf sunumsal parçaları çıkarın:
Önce kopyala-ve-bağla, sonra temizle. UI güvenle bölündükten sonra state/efekt adımlarına geçin.
Gerçek kimliğe bağlı, istikrarlı anahtarlar (ID gibi) kullanın; dizi indeksleri tehlikelidir.
İndeks anahtarlar sıralama, filtreleme, ekleme veya silme durumlarında yanlış örneklerin yeniden kullanılmasına yol açar ve şu hatalara sebep olabilir:
Eğer refaktör anahtarları değiştiriyorsa bunu yüksek riskli kabul edin ve yeniden sıralama durumlarını test edin.
Türev verileri useState içinde tutmayın; bunları prop, state ve çekilen veriden hesaplayın.
Güvenli yaklaşım:
filteredRows gibi) mevcut girdilerden hesaplayınuseMemo kullanınBu, güncelleme tuhaflıklarını azaltır ve bileşeni daha kolay anlaşılır kılar.
Adım adım checkpoint döngüsü:
Koder.ai kullanıyorsanız snapshot'lar normal commit'leri tamamlayıcı olarak işe yarar.
Davranış kilitlenmiş ve kod daha kolay değiştirilebilir olduğunda durun. Durma sinyalleri:
Refaktörü gönderin; kalan erişilebilirlik, performans ve temizlik işlerini ayrı işler olarak kaydedin.