React Native’de performans tartışmalarının çoğu ölçümsüzdür: “FlatList yavaş”, “New Arch açınca düzelir”. Senior refleks tersidir — önce metrik, sonra hipotez, sonra patch.
Yanlış katmanı optimize etmek — UI thread problemini React.memo ile “çözmek” — en pahalı hatadır.
İki FPS vardır: JS ve UI
Tek bir “FPS” sayısı yanıltıcıdır. İki bağımsız frame bütçesi vardır (~16ms @ 60Hz):
| Metrik | Ne ölçer | Düşükse tipik suçlu |
|---|---|---|
| JS FPS | JavaScript thread | Ağır render, büyük JSON parse, sync JSI suiistimali |
| UI FPS | Native UI thread | Overdraw, blur, layout thrash, image decode, worklet overload |
JS 60 iken UI 40 olabilir — veya tersi. Perf Monitor veya platform profiler ile ayırın. Scroll jank genelde UI’de; liste filtreleme gecikmesi JS’te.
Neden ayrım kritik?
New Architecture (Fabric / Turbo) bazı UI maliyetlerini düşürür; JS render patolojisini iyileştirmez. Metrik ayrımı doğru müdahale katmanını seçtirir.
TTI ve cold start
TTI (Time to Interactive — etkileşilebilir ilk ekrana süre) bileşenleri:
- Process start + native init
- Hermes
.hbc(bytecode) load ve VM init - React root mount + ilk render
- İlk data (cache hit vs network)
Araç notu:
# Android: Perfetto trace + logcat ActivityManager displayed
# iOS: Instruments App Launch template + Time Profiler
Optimizasyon sırası genelde: eager native init azalt → bundle boyutu / inlineRequires → ilk ekran ağacını küçült → data prefetch. “Tüm tab navigator’ı hemen mount” anti-pattern’ini ölçmeden savunmayın.
TTI’yi p50 ve p95 olarak raporlayın. Ortalama yanıltır.
Cold vs warm start
Cold: process yok, sıfırdan. Warm: process bellekte. Kullanıcı ilk izlenimi cold start’a bakar.
Araç seti
JavaScript
- React DevTools Profiler: commit süreleri, hangi component ne kadar render oldu
- Hermes sampling profiler: JS CPU hot spot
- Hermes heap snapshot: memory leak vs cache
Android
- Perfetto / systrace: JS Thread, UI Thread, Choreographer
- Android Studio Profiler: native + ART
- GPU Rendering profile: overdraw
- Macrobenchmark (CI): regresyon
iOS
- Instruments: Time Profiler, Allocations, Core Animation
- MetricKit (production): gerçek kullanıcı TTI
Reanimated kullanan ekranlarda JS FPS iyi, UI FPS düşük → worklet veya layout animasyonu şüpheli.
Darboğaz sınıfları
1. Gereksiz re-render
Context god-object, inline style={{}} ile memo kırılması. Müdahale: context split, selector pattern, bilinçli memo.
2. Liste performansı
Kötü key, getItemLayout eksikliği, nested VirtualizedList. FlashList gibi alternatifleri ölçmeden adopt etmeyin.
3. Bridge / serileştirme fırtınası
Henüz Turbo’ya geçmemiş hot path’te saniyede yüzlerce native çağrı. Müdahale: batch API, Turbo Module migrasyonu.
4. Görsel yük
Dev boyut PNG, cache yok, simultaneous decode. FastImage + boyut optimizasyonu.
5. Navigation remount
Her focus’ta heavy screen remount. detachInactiveScreens, lazy screen options.
Metodoloji: runbook
- Repro yaz: cihaz, OS, adım adım
- Baseline kaydet: video + FPS overlay + trace
- Tek hipotez: birden fazla değil
- Tek değişiklik: PR’da tek optimizasyon
- Aynı trace ile karşılaştır
- Kazanç yoksa geri al
Golden trace senaryolarını repo’da saklayın.
New Architecture etkisi
Fabric/Turbo bazı senaryolarda jank’i azaltır. JS render patolojisini iyileştirmez. New Arch’a “perf projesi” diye geçmeyin; migrasyon ve perf ayrı paket olsun.
Production checklist
- JS vs UI FPS ayrı raporlanıyor
- Low-end Android cihazda ölçüldü
- Release profili alındı (minify + Hermes + R8)
- Memory leak vs intentional cache ayrımı yapıldı
- Liste ekranları için scroll trace arşivlendi
- TTI p50/p95 production metrik
- Golden trace senaryoları dokümante
- Optimizasyon PR’ları tek hipotez kuralına uyuyor
Özet
Performans tahmin değil, ölçüm işidir. RN’de en pahalı hata yanlış katmanı optimize etmektir. JS FPS mi UI FPS mi düşük — bu sorunun cevabı tüm müdahale stratejinizi belirler.