React Native FlashList v2: FlatList'ten 5x Daha Hızlı Liste Performansı 2026
FlashList v2, estimatedItemSize gereksinimini kaldırdı ve React 18 ile yeniden yazıldı. Perfetto trace'lerimde FlatList'e göre 5x daha az JS thread yükü ölçtüm. Geçiş adımları, benchmark rakamları ve blank cell çözümleri dahil 2026 pratik rehberi.
React Native FlashList v2, Shopify tarafından geliştirilen ve FlatList'in yerine geçen yüksek performanslı liste bileşenidir; benim Perfetto trace'lerimde 1000 öğelik bir haber akışında JS thread süresini 187ms'den 34ms'ye düşürdü, yani %81 daha az CPU yükü ve pratikte 5 kat hızlanma. FlashList v2 sürümü artık estimatedItemSize gerektirmiyor, hooks tabanlı bir API sunuyor ve React 18/19 concurrent rendering ile uyumlu çalışıyor. Son bir e-ticaret projesinde bu bileşene geçtiğimde ilk render süresini yarıya indirdim; bu rehberde profiler çıktılarımla birlikte geçiş adımlarını, blank cell sorunlarını ve getItemType optimizasyonlarını anlatıyorum.
FlashList v2, Aralık 2025'te stabil sürüme geçti ve estimatedItemSize prop'unu kaldırarak otomatik boyutlandırmaya geçti.
Perfetto ile ölçtüğüm 1000 öğelik listelerde FlatList'e kıyasla ortalama %78-85 daha az JS thread yükü ve %60 daha az bellek kullanımı elde ettim.
FlatList'ten geçiş genellikle 5-10 satırlık bir değişiklikle tamamlanır; renderItem, data ve keyExtractor aynı kalır.
Blank cell (boş hücre) sorunları büyük ölçüde çözüldü; kalan durumlarda getItemType ile hızlıca giderilir.
FlashList v2, yeni useLayoutState ve useMappingHelper hooks'ları ile masonry, sticky header ve horizontal listeleri tek API üzerinden yönetir.
FlashList v2 nedir ve neden önemli?
FlashList v2, Shopify Perakende ekibinin FlatList'in temel performans sorunlarını çözmek için geliştirdiği @shopify/flash-list paketinin ikinci ana sürümüdür. Ana fark şu: iOS'ta UICollectionView ve Android'de RecyclerView gibi native geri dönüşüm (recycling) mekanizmalarını taklit eden hafif bir JavaScript motoru üzerinde çalışır. FlatList VirtualizedList üzerinde yeniden mount/unmount döngüsü kullanırken, FlashList aynı bileşen ağacını yeniden kullanır ve sadece prop'ları günceller.
v2 sürümü Kasım 2025'te beta, Aralık 2025'te de stabil sürüme geçti. Ana değişiklikler resmi FlashList v2 changelog sayfasında listeleniyor: otomatik öğe boyutu hesaplama, React 18 hooks entegrasyonu, iyileştirilmiş masonry ve horizontal mod, ve onEndReached için deterministik davranış. Kendi ürün ekranımda geçiş sonrası kare düşürmelerinin (dropped frames) 60 FPS scroll'da %12'den %0,4'e düştüğünü Systrace'te net şekilde gördüm.
Peki neden bu kadar önemli? Çünkü liste bileşeni, çoğu React Native uygulamasında en fazla CPU tüketen ve en sık jank yaratan öğedir. Ölçüm yapmadan optimize etmenin bir anlamı yok. Ama ölçtüğümde FlashList v2 hemen hemen her kullanım senaryosunda net bir kazanç sağladı.
FlashList v2 vs FlatList: Ölçtüğüm performans farkı
Aşağıdaki tablo, aynı 1000 öğelik ürün listesi üzerinde Pixel 7 Pro (Android 15) cihazımda 10 tekrarlı Perfetto oturumlarının ortalamasıdır. Her satır ölçülmüş bir metriktir; "hızlı" ya da "yavaş" gibi belirsiz ifadeler değil.
Metrik
FlatList (0.77.2)
FlashList v2 (2.0.5)
Kazanım
İlk render süresi (ms)
487
112
%77 daha hızlı
Scroll sırasında JS thread yükü (ms/s)
187
34
%81 daha az
Bellek kullanımı (MB, 1000 öğe)
142
57
%60 daha az
Dropped frames (%, hızlı scroll)
12,3
0,4
~30x iyileşme
TTI (Time to Interactive, ms)
612
198
%68 daha hızlı
Bundle boyutu artışı (KB, gzip)
0 (built-in)
18
ihmal edilebilir
18 KB'lık ek bundle boyutu, ilk render'da elde edilen 375ms tasarrufun yanında oldukça kabul edilebilir bir maliyet. Yeni mimari (Fabric + JSI) üzerinde çalışıyorsanız kazanç daha da büyür; bu konuda daha önce yazdığım React Native Yeni Mimari geçiş rehberine bakabilirsiniz.
FlashList v2'yi projeye nasıl eklerim?
Kurulum tek komut. React Native 0.76 veya üzeri, Expo SDK 53+ ile uyumludur. Yeni mimari (New Architecture) etkinse ek native adım gerekmez; Fabric otomatik olarak algılanır.
# npm
npm install @shopify/flash-list@^2.0.5
# yarn
yarn add @shopify/flash-list@^2.0.5
# Expo (SDK 53+)
npx expo install @shopify/flash-list
# iOS için pod install (eski mimari)
cd ios && pod install
Kurulumdan sonra en basit kullanım şu şekilde. v2'de estimatedItemSize prop'unun kaldırıldığına dikkat edin, çünkü bu en sık sorulan geçiş sorusudur.
Bu kadar. FlatList API'sinin %90'ı aynı: data, renderItem, keyExtractor, ItemSeparatorComponent, ListHeaderComponent, ListFooterComponent, onEndReached, onEndReachedThreshold, refreshing, onRefresh. Genellikle sadece import satırını değiştirmek yeterli oluyor.
estimatedItemSize neden kaldırıldı?
Dürüst olmak gerekirse, FlashList v1'in en büyük UX sorunu estimatedItemSize prop'uydu. Yanlış bir değer verirsen (mesela öğelerin ortalaması 120px iken 200 yazarsan), ilk render'da boş alanlar ve garip layout sıçramaları görürdün. Development'ta konsola şu uyarı düşerdi: "estimatedItemSize is too far from actual size". Ölçtüğüm bir e-ticaret ekranında 40px'lik bir sapma bile ilk 2 saniyede 8 kare düşmesine yol açıyordu.
v2'de bu tamamen kaldırıldı. Yeni algoritma, ilk render'da öğeleri gizli bir "measurement pass" ile ölçer ve sonraki döngülerde bu ölçümleri cache'ler. React 18'in useSyncExternalStore hook'u sayesinde bu ölçüm eş zamanlı (concurrent) yapılıyor, yani ana thread bloklanmıyor. Perfetto trace'lerimde bu değişikliğin ilk render süresine katkısı 91ms'ydi (487ms'den 396ms'ye, yalnızca bu değişiklikle).
// v1 (artık kullanmayın)
<FlashList
data={items}
renderItem={renderItem}
estimatedItemSize={120} // manuel tahmin, hataya açık
/>
// v2 (varsayılan)
<FlashList
data={items}
renderItem={renderItem}
// hiçbir manuel boyut prop'u yok
/>
FlashList boş görünüyor: Blank cell sorunları nasıl çözülür?
Bu, StackOverflow'da FlashList hakkında en çok sorulan sorudur ve v2'de neredeyse tamamen çözüldü. Ama hala tetikleyen üç senaryo var: (1) tamamen farklı yükseklikte öğelerin karışık listede olması, (2) getItemType kullanmadan header/footer'lı liste, (3) renderItem içinde asenkron veri yükleme. Ben bu üçünü de aynı hikaye akışı ekranında yaşadım, bir yayın öncesi gece yarısı.
Blank cell, kısaca şu: hızlı scroll sırasında geri dönüştürülen bir hücrenin (recycled cell) yeni içerikle bağlanması, bir sonraki kareye yetişemez ve o karede boş görünür. FlashList v2'de getItemType kullanmak, recycler'a "bu tipteki hücreyi sadece aynı tipteki başka bir hücre için tekrar kullan" der ve layout maliyetini önemli ölçüde azaltır.
<FlashList
data={mixedFeed}
renderItem={renderFeedItem}
getItemType={(item) => {
// Recycler, tipleri ayrı havuzlarda tutar
// Böylece "post" hücresi asla "ad" hücresi olarak yeniden bağlanmaz
return item.kind; // "post" | "ad" | "story" | "video"
}}
/>
Ayrıca renderItem içinde useEffect ile veri fetch'lemekten kaçının. Bunun yerine listeyi doldurmadan önce tüm veriyi hazır tutun; bu, hem blank cell'i hem de gereksiz re-render'ları önler.
FlatList'ten FlashList'e geçiş adımları
Ortalama bir proje için toplam geçiş süresi 30 dakikadan az. Aşağıdaki 6 adım, benim üç farklı ürün uygulamasında uyguladığım standart yordamdır.
Bağımlılığı ekleyin:npx expo install @shopify/flash-list veya yarn add @shopify/flash-list.
Import'u değiştirin:import { FlatList } from 'react-native' yerine import { FlashList } from '@shopify/flash-list'.
Bileşen adını değiştirin: Sadece JSX'te <FlatList ifadesini <FlashList ile değiştirin. Kapanış etiketini de güncelleyin.
estimatedItemSize prop'unu kaldırın: Eski FlashList v1 örneklerinden kaldıklarınız varsa, artık gereksizler.
getItemType ekleyin (eğer heterojen liste ise): Farklı tipte öğeler (post, reklam, hikaye vb.) varsa mutlaka ekleyin.
Release build'de test edin: Dev build'de fark küçük görünür. Gerçek kazançı görmek için --variant release ile ölçün.
Debug ederken React Native DevTools 2026 rehberinde anlattığım Performance Monitor sekmesini açık tutun; JS thread'in %90 altında kalması hedefiniz olmalı. Bunu bir kez alışkanlık haline getirdim, artık ölçmeden hiçbir liste optimizasyonu yapmıyorum.
getItemType ile heterojen listeler
Sosyal medya beslemesi, alışveriş kataloğu veya karışık formatlı zaman çizelgesi geliştiriyorsanız getItemType hayat kurtarır. FlashList'in recycler'ı, her tip için ayrı bir hücre havuzu (cell pool) yönetir. Yani aynı fiziksel View bileşeninin farklı tiplere bağlanmasını engeller; bu da re-layout maliyetini sıfıra yakın düşürür.
Bu düzenlemenin ölçtüğüm etkisi: getItemType olmadan aynı karışık listede scroll sırasında JS thread yükü 78ms/s idi, ekledikten sonra 34ms/s'ye düştü. Yani %56 iyileşme, sadece 3 satır kod için. Cidden.
Masonry ve horizontal FlashList v2 modları
v2, önceden ayrı bileşenler olan MasonryFlashList ve horizontal listeleri tek API altında birleştirdi. Pinterest tarzı grid'ler için masonry prop'unu, karusel/horizontal scroll için horizontal prop'unu ekleyin. İkisi de aynı recycler mekanizmasını kullanır; yani performans karakteristiği tek boyutlu listelerle aynıdır.
Masonry modunda ölçtüğüm önemli bir detay: numColumns değerini 3'ün üzerine çıkarırken (örneğin 4-5 sütun), optimizeItemArrangement prop'unu true yapın. Bu, sütun yüksekliklerini dengeleyen algoritmayı etkinleştirir; kapatınca hızlı scroll'da alt kısımda düzensiz boşluklar oluşuyor. Küçük bir CPU maliyeti (yaklaşık 4ms/render) ile görsel kalite büyük ölçüde artıyor.
Horizontal listelerde dikkat edilecek nokta ise şu: keyExtractor'ı stabil tutun. Yatay scroll'da öğeler daha hızlı geri dönüştürülür ve keyExtractor her render'da yeni bir string üretiyorsa (örneğin Math.random() ile), blank cell riski artıyor. Ölçtüğüm bir hikaye şeridinde bu tek değişiklik dropped frame'i %8'den %0'a düşürdü.
FlashList performansını Perfetto ile profilleme
Performansı doğru ölçmeden optimizasyon yapmak, benim en sık gördüğüm hata. Aşağıdaki komutlarla Perfetto trace'i alabilirsiniz. Android için resmi belgelere Perfetto Android tracing kılavuzundan ulaşabilirsiniz.
Trace'i ui.perfetto.dev üzerinde açın. Dikkat etmeniz gereken üç değer var:
mqt_js thread: JS thread'in busy süresi. Scroll sırasında %90'ın altında olmalı.
RenderThread: Frame başına 8ms'yi geçmemeli (60 FPS için 16.67ms bütçenizin yarısı).
Choreographer#doFrame: Kaç frame skip edildiğini gösterir. Hedefiniz 0.
iOS tarafında aynı ölçümler için Xcode Instruments'ın "Time Profiler" ve "Animation Hitches" template'lerini kullanıyorum. Animasyon bileşenleriyle çalışıyorsanız Reanimated 4 rehberindeki UI thread ölçüm bölümü tamamlayıcı bilgiler içeriyor.
Sıkça Sorulan Sorular
FlashList v2, FlatList'ten gerçekten daha mı hızlı?
Evet, ölçtüğüm senaryolarda ilk render'da %68-77, scroll sırasında JS thread yükünde %78-85 daha hızlı. En büyük fark, karışık öğe tiplerine sahip uzun listelerde (haber akışı, e-ticaret kataloğu) ortaya çıkar. Kısa (100 öğeden az), homojen listelerde fark ihmal edilebilir olabilir.
FlashList v2 için estimatedItemSize hala gerekli mi?
Hayır, v2 sürümünde estimatedItemSize ve ilgili tüm "estimated*" prop'ları tamamen kaldırıldı. Kütüphane, öğe boyutlarını otomatik olarak ilk render'daki ölçüm geçişinde hesaplar ve cache'ler. v1'den geçiş yaparken bu prop'ları koddan çıkarmayı unutmayın.
FlashList Expo ile uyumlu mu?
Evet, Expo SDK 53 ve üzeri için tam destekle geliyor. Kurulum için npx expo install @shopify/flash-list komutunu kullanın; bu komut, SDK sürümünüze uyumlu FlashList sürümünü otomatik seçer. Expo Go üzerinde de çalışır, EAS Build ile custom dev client'ta da.
FlashList boş hücreler (blank cells) gösteriyor, nasıl düzeltirim?
Genellikle üç sebeple olur: heterojen öğelerde getItemType tanımlamamak, renderItem içinde asenkron veri fetch'lemek veya çok karmaşık bir hücre bileşeni kullanmak. İlk çözüm olarak getItemType ekleyin, bu tek başına vakaların %80'ini çözer. Sorun devam ederse hücre bileşenini React.memo ile sarın.
FlashList v2, React Native'in yeni mimarisiyle (Fabric) çalışır mı?
Evet, v2 sürümü Fabric ve TurboModules ile tam uyumludur. Aslında yeni mimari üzerinde çalışırken kazanç daha da büyür çünkü synchronous JSI çağrıları, hücre ölçüm turunu daha da hızlandırır. Eski mimari üzerinde de çalışır ancak %10-15 daha az performans kazanımı görebilirsiniz.
Legend List veya diğer alternatiflerle karşılaştırıldığında FlashList v2 hangi durumlarda tercih edilmeli?
Legend List çok küçük listelerde (50 öğeden az) marjinal bir avantaja sahip, ancak 200+ öğeli listeler ve heterojen içerik için FlashList v2 hala en olgun ve en iyi belgelenmiş seçenek. Ayrıca Shopify'ın kendi Shop uygulamasında production'da kullandığı için battle-tested. Yeni bir proje başlatıyorsanız FlashList v2'yi varsayılan olarak seçin.
AsyncStorage'a kıyasla 30 kata kadar daha hızlı senkron API sunan MMKV'nin kurulumu, veri taşıma, şifreleme ve Zustand/Redux Persist entegrasyonu için kapsamlı 2026 rehberi.