# 2026'da Hızlı JavaScript ListView: Windowing, Sanallaştırma ve Performans Optimizasyonu > JavaScript'te binlerce öğeyi render etmek için windowing ve sanallaştırma tekniklerini keşfedin. TanStack Virtual, react-virtuoso ve 2026'da verimli listeler için en iyi uygulamalar. - Published: 2026-09-15 - Updated: 2026-09-15 - Author: Anthony Fillion-Maillet - Reading time: 5 min --- Sanallaştırma olmadan bir JavaScript ListView'de binlerce öğeyi render etmek, tarayıcının binlerce DOM düğümü oluşturmasına neden olur ve bu da yavaş ilk render süreleri, takılan kaydırma ve mobil cihazları çökertebilecek bellek tüketimine yol açar. 2026'da hızlı JavaScript ListView uygulamaları bu sorunu windowing ile çözer: viewport'ta görünen yalnızca 10-20 öğeyi render ederken tüm öğeleri içeren kaydırılabilir bir alan simüle eder. > **Windowing Tek Cümlede** > > Windowing yalnızca görünür öğeleri ve küçük bir tampon (overscan) render eder, DOM düğümlerini liste boyutundan bağımsız olarak 10.000'den yaklaşık 20'ye düşürür. ## Büyük Listelerde Tarayıcı Performansı Neden Düşer Her DOM düğümü bellek tüketir ve tarayıcının düzen hesaplamaları sırasında konumunu takip etmesini gerektirir. Orta düzeyde karmaşık işaretlemeye sahip 10.000 öğelik bir liste (avatar, iki metin spanı, bir düğme) 40.000'den fazla DOM düğümü oluşturur. Chrome'un render motoru, her kaydırma olayında hepsi için stilleri ve konumları yeniden hesaplar. Sonuç: ilk render 2-4 saniye sürer, kaydırma 15fps'ye düşer ve bellek kullanımı 500MB'ı aşar. Mobil Safari'de sekme genellikle tamamen çöker. Sanallaştırma, sabit bir DOM düğüm sayısı tutarak bu sorunu çözer. Veri dizisi 100 veya 100.000 öğe içerse de, render edilen DOM yaklaşık 20-30 düğümde kalır, bellek tüketimini sabit tutar ve kaydırma performansını 60fps'de korur. ```typescript // VirtualizedList.tsx import { useVirtualizer } from '@tanstack/react-virtual' import { useRef } from 'react' interface Item { id: string name: string email: string } export function VirtualizedList({ items }: { items: Item[] }) { const parentRef = useRef(null) // Create virtualizer instance with estimated row height const virtualizer = useVirtualizer({ count: items.length, getScrollElement: () => parentRef.current, estimateSize: () => 60, // estimated height in pixels overscan: 5, // render 5 extra items above/below viewport }) return (
{virtualizer.getVirtualItems().map((virtualRow) => { const item = items[virtualRow.index] return (

{item.name}

{item.email}

) })}
) } ``` Bu uygulama yalnızca görünür satırları ve overscan tamponunu render eder. Dış konteyner toplam kaydırılabilir yüksekliği ayarlar ve kaydırma çubuğunun tüm öğeler DOM'da varmış gibi davranmasını sağlar. ## TanStack Virtual: 2026 İçin Başsız Yaklaşım [TanStack Virtual](https://tanstack.com/virtual/latest) framework-agnostik sanallaştırma primitifleri sağlar. react-window veya react-virtuoso'dan farklı olarak, önceden oluşturulmuş bileşenler sunmaz - yalnızca hangi öğelerin render edileceğini ve nereye konumlandırılacağını hesaplayan hook'lar sunar. Bu başsız mimari, stiller ve DOM yapısı üzerinde tam kontrol anlamına gelir. Mevcut sürüm (3.13) React, Vue, Solid, Svelte ve vanilla JavaScript'i destekler. Temel yapılandırma seçenekleri: | Seçenek | Amaç | Varsayılan | |--------|---------|--------| | `count` | Toplam öğe sayısı | zorunlu | | `estimateSize` | Tahmini öğe yüksekliği/genişliği döndüren fonksiyon | zorunlu | | `overscan` | Viewport dışında render edilen ekstra öğeler | 1 | | `getScrollElement` | Kaydırılabilir konteyneri döndürür | zorunlu | | `measureElement` | Dinamik boyutlar için özel ölçüm fonksiyonu | otomatik | `overscan` değeri doğrudan kaydırma akıcılığını etkiler. Çok düşük ayarlamak (0-2) hızlı kaydırma sırasında beyaz yanıp sönmelere neden olur. Çok yüksek ayarlamak (20+) sanallaştırma faydalarını ortadan kaldırır. Çoğu uygulama için 5-10 optimal dengeyi sağlar. ```typescript // DynamicHeightList.tsx import { useVirtualizer } from '@tanstack/react-virtual' import { useRef, useCallback } from 'react' interface Message { id: string content: string timestamp: number } export function ChatList({ messages }: { messages: Message[] }) { const parentRef = useRef(null) // measureElement enables dynamic height measurement const virtualizer = useVirtualizer({ count: messages.length, getScrollElement: () => parentRef.current, estimateSize: () => 80, // rough estimate, actual measured later overscan: 8, }) return (
{virtualizer.getVirtualItems().map((virtualRow) => { const message = messages[virtualRow.index] return (

{new Date(message.timestamp).toLocaleTimeString()}

{message.content}

) })}
) } ``` `measureElement` ref'i render sonrasında otomatik yükseklik ölçümünü etkinleştirir. Bu, manuel yükseklik hesaplaması gerektirmeden değişken içerik uzunluklarını yönetir. ## react-virtuoso: Zengin Özellikli Alternatif [react-virtuoso](https://virtuoso.dev/) tam tersi yaklaşımı benimser: her şey dahil bir bileşen kütüphanesi. TanStack Virtual kaydırma konteyneri ve konumlandırma mantığı oluşturmayı gerektirirken, react-virtuoso bunları dahili olarak yönetir. Takas, paket boyutudur (TanStack Virtual için 37KB vs 12KB) ancak gruplandırılmış listeler, yapışkan başlıklar ve ters kaydırmalı sohbet arayüzleri gibi yaygın kalıplar için önemli ölçüde daha az şablon kod gerektirir. ```typescript // VirtuosoList.tsx import { Virtuoso } from 'react-virtuoso' interface User { id: string name: string department: string } export function UserDirectory({ users }: { users: User[] }) { return ( (
{user.name.charAt(0)}

{user.name}

{user.department}

)} /> ) } ``` Bu, daha az kodla aynı sanallaştırma sonucunu elde eder. react-virtuoso otomatik olarak öğeleri ölçer, dinamik yükseklikleri yönetir ve kaydırma pozisyonu kalıcılığı sağlar. [React performansı üzerine mülakat hazırlığı](/technologies/react-next/interview-questions/styling-css-in-js) için her kütüphanenin ne zaman seçileceğini anlamak mimari farkındalığı gösterir. TanStack Virtual, zaten TanStack Table kullanan veya framework-agnostik kod gerektiren uygulamalara uygundur. react-virtuoso, geliştirme hızını paket boyutuna tercih eden ekiplere uygundur. ## Yaygın Tuzaklar ve Çözümler ### Görsellerle Kaydırma Pozisyonu Atlamaları Görseller asenkron olarak yüklenir ve ilk ölçümden sonra satır yüksekliğini değiştirir. Sanallaştırıcı bu değişikliği tahmin edemez ve alttaki içeriğin kaymasına neden olur. Çözüm: aspect-ratio veya sabit boyutlar kullanarak görseller için yer ayırmak. ```typescript // ImageListItem.tsx interface ImageItem { id: string src: string title: string } export function ImageListItem({ item }: { item: ImageItem }) { return (
{/* Reserve 80x80px space regardless of load state */}
{item.title}

{item.title}

) } ``` ### Kaydırma Sırasında Durum Kaybı Sanallaştırılmış öğeler görünüm alanından çıkınca unmount olur. Herhangi bir yerel durum (form girdileri, genişletilmiş akordeonlar) kaybolur. Çözüm: durumu üst bileşene veya öğe ID'sine göre anahtarlanmış bir durum yönetimi kütüphanesine taşımak. ```typescript // ExpandableList.tsx import { useState, useCallback, useRef } from 'react' import { useVirtualizer } from '@tanstack/react-virtual' interface FAQ { id: string question: string answer: string } export function FAQList({ faqs }: { faqs: FAQ[] }) { // State lives in parent, survives row unmounting const [expandedIds, setExpandedIds] = useState>(new Set()) const parentRef = useRef(null) const toggleExpanded = useCallback((id: string) => { setExpandedIds(prev => { const next = new Set(prev) if (next.has(id)) { next.delete(id) } else { next.add(id) } return next }) }, []) const virtualizer = useVirtualizer({ count: faqs.length, getScrollElement: () => parentRef.current, estimateSize: () => 60, overscan: 5, }) return (
{virtualizer.getVirtualItems().map((virtualRow) => { const faq = faqs[virtualRow.index] const isExpanded = expandedIds.has(faq.id) return (
) })}
) } ``` ### Yeniden Renderlara Neden Olan Kararsız Anahtarlar Dizi indekslerini anahtar olarak kullanmak, liste yeniden sıralanana kadar çalışır. Öğeler yanlış durum alır ve görsel hatalara ve boşa harcanan renderlara neden olur. Her zaman verinin kendisinden kararlı, benzersiz tanımlayıcılar kullanılmalıdır: ```typescript // Correct: stable key from data {virtualizer.getVirtualItems().map((virtualRow) => { const item = items[virtualRow.index] return
...
// id from database/API })} // Wrong: index changes when list reorders {virtualizer.getVirtualItems().map((virtualRow, index) => { return
...
// causes bugs on reorder })} ``` ## 2026 Projeleri İçin Kütüphane Karşılaştırması Doğru sanallaştırma kütüphanesini seçmek proje gereksinimlerine bağlıdır. Bu karşılaştırma 2026 ekosistemini yansıtır: | Kriter | TanStack Virtual | react-virtuoso | react-window | |----------|-----------------|----------------|---------------| | Paket boyutu | 12KB | 37KB | 6KB | | Dinamik yükseklikler | Manuel kurulum | Otomatik | Desteklenmiyor | | TypeScript | Yerel | Yerel | @types paketi | | Framework desteği | React, Vue, Solid, Svelte | Yalnızca React | Yalnızca React | | Bakım | Aktif (2026) | Aktif (2026) | Bakım modu | | Öğrenme eğrisi | Daha yüksek | Daha düşük | En düşük | react-window, paket boyutunun önemli olduğu basit sabit yükseklikli listeler için hala geçerlidir. Ancak bakım modu durumu ve dinamik yükseklik desteği eksikliği, karmaşık gereksinimleri olan yeni projeler için uygun değildir. [Performanslı React uygulamaları oluşturmak](/blog/react-next/react-testing-2026-vitest-rtl-best-practices) için sanallaştırma takaslarını anlamak, mülakatçıların aradığı performans farkındalığını gösterir. ## Performans İyileştirmelerini Ölçme Sanallaştırma faydalarını ölçmek tutarlı bir ölçüm metodolojisi gerektirir. Chrome DevTools Performance paneli ilgili metrikleri sağlar. Sanallaştırma öncesi/sonrası temel ölçümler: - **First Contentful Paint (FCP)**: İlk içerik render edilene kadar geçen süre. Sanallaştırma, ilk DOM oluşturmayı sınırlayarak bunu azaltır. - **Total Blocking Time (TBT)**: Yükleme sırasında ana thread engelleme. Daha az DOM düğümü, daha az stil/düzen hesaplaması anlamına gelir. - **Bellek kullanımı**: Memory panelinde heap boyutu snapshot'ı. Liste uzunluğundan bağımsız olarak sabit kalmalıdır. - **Kaydırma fps**: Kaydırma sırasında Performance izi kaydedin. Kare hızı 60fps'de kalmalıdır. ```typescript // PerformanceMonitor.tsx import { useEffect, useRef } from 'react' export function useScrollFPS(containerRef: React.RefObject) { const frameCountRef = useRef(0) const lastTimeRef = useRef(performance.now()) useEffect(() => { const container = containerRef.current if (!container) return let rafId: number const measureFrame = () => { frameCountRef.current++ const now = performance.now() if (now - lastTimeRef.current >= 1000) { console.log(`Scroll FPS: ${frameCountRef.current}`) frameCountRef.current = 0 lastTimeRef.current = now } rafId = requestAnimationFrame(measureFrame) } const handleScroll = () => { if (!rafId) { rafId = requestAnimationFrame(measureFrame) } } container.addEventListener('scroll', handleScroll, { passive: true }) return () => { container.removeEventListener('scroll', handleScroll) cancelAnimationFrame(rafId) } }, [containerRef]) } ``` Bu hook geliştirme sırasında kaydırma FPS'ini loglar. Üretim uygulamaları Sentry Performance veya özel telemetri gibi gözlemlenebilirlik araçları kullanmalıdır. ## JavaScript Liste Performansı İçin Temel Çıkarımlar - Sanallaştırma, DOM düğümlerini binlerden yaklaşık 20'ye düşürür ve veri boyutundan bağımsız olarak bellek ve kaydırma performansını sabit tutar - TanStack Virtual (12KB), React, Vue, Solid ve Svelte'de maksimum kontrol için başsız primitifler sağlar - react-virtuoso (37KB), otomatik dinamik yükseklik yönetimi ile her şey dahil bileşenler sunar - react-window 2022'den beri bakım modunda ve dinamik yükseklikleri desteklemiyor - Overscan'i 5-10 arasında ayarlamak, sanallaştırma faydalarını ortadan kaldırmadan optimal kaydırma akıcılığı sağlar - Görsel boyutlarını rezerve etmek, asenkron yükleme sırasında kaydırma pozisyonu atlamalarını önler - Genişletilebilir/düzenlenebilir durumu üst bileşene taşıyın çünkü sanallaştırılmış satırlar kaydırma sırasında unmount olur - Yeniden sıralamada durum uyuşmazlıklarını önlemek için dizi indeksleri yerine veri ID'lerinden kararlı anahtarlar kullanın - İyileştirmeleri ölçmek için uygulama öncesi/sonrası FCP, TBT, bellek ve kaydırma FPS'ini ölçün --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/tr/blog/node-nestjs/fast-javascript-listview-2026-windowing-virtualization-performance