2026'da Yüksek Performanslı JavaScript ListView: Sanallaştırma ve Optimizasyon Teknikleri
TanStack Virtual, react-virtuoso ve react-window ile JavaScript liste sanallaştırmasında uzmanlaşın. Windowing teknikleriyle 100 binden fazla öğeyi akıcı şekilde render edin.

Yüksek performanslı JavaScript ListView render işlemi, uygulamaların tarayıcıyı dondurmadan binlerce öğe görüntülemesi gerektiğinde kritik hale gelir. Liste sanallaştırması, DOM düğümlerini geri dönüştürürken yalnızca görünür öğeleri render etme tekniği, ağır kaydırma deneyimlerini pürüzsüz etkileşimlere dönüştürür.
Sanallaştırma, yalnızca viewport içinde görünen öğeleri ve küçük bir overscan tamponunu render eder. 10 görünür satırı olan 100.000 öğelik bir liste, 100.000 yerine yalnızca 15-20 DOM düğümü oluşturur ve bellek kullanımını yüzlerce megabyte'tan kilobyte'lara düşürür.
DOM Düğüm Sayısı Neden Kaydırma Performansını Yok Eder
Tarayıcılar büyük DOM ağaçlarıyla zorlanır. Her düğüm, elementin kendisi, hesaplanmış stilleri ve düzen verileri için bellek gerektirir. 5.000 düğümün ötesinde, reflow'lar fark edilir hale gelir. 50.000 düğümde, kaydırma olayları 100ms'den fazla sürebilir ve görünür takılmalara neden olur.
Performans maliyeti doğrusal olmayan şekilde artar. Chrome'un render pipeline'ı şunları yapmalıdır:
- JavaScript olay işleyicilerini çalıştır
- Etkilenen elemanlar için stilleri yeniden hesapla
- Düzen konumlarını hesapla
- Pikselleri katmanlara çiz
- Son görüntü için katmanları birleştir
Sanallaştırma, ekran dışı öğeler için 2-4 adımlarını tamamen ortadan kaldırır. Tarayıcı, veri uzunluğundan bağımsız olarak sabit bir DOM boyutu korur.
TanStack Virtual: Başsız Sanallaştırma Standardı
TanStack Virtual, framework bağımsız sanallaştırma primitifleri sağlar. Sürüm 3.13 (Ağustos 2026'da yayınlandı) önemli performans iyileştirmeleri getirdi: 100.000 öğe için soğuk mount 6,1ms'den 4,5ms'ye düştü ve en kötü durum yeniden boyutlandırma senaryosu 2 saniyeden 1,3 milisaniyeye iyileşti.
import { useVirtualizer } from '@tanstack/react-virtual'
import { useRef } from 'react'
interface VirtualListProps<T> {
items: T[]
estimateSize: number
renderItem: (item: T, index: number) => React.ReactNode
}
export function VirtualList<T>({ items, estimateSize, renderItem }: VirtualListProps<T>) {
const parentRef = useRef<HTMLDivElement>(null)
const virtualizer = useVirtualizer({
count: items.length,
getScrollElement: () => parentRef.current,
estimateSize: () => estimateSize,
overscan: 5, // Viewport'un üstünde/altında 5 ekstra öğe render et
})
return (
<div ref={parentRef} style={{ height: '100%', overflow: 'auto' }}>
<div
style={{
height: `${virtualizer.getTotalSize()}px`,
width: '100%',
position: 'relative',
}}
>
{virtualizer.getVirtualItems().map((virtualItem) => (
<div
key={virtualItem.key}
style={{
position: 'absolute',
top: 0,
left: 0,
width: '100%',
height: `${virtualItem.size}px`,
transform: `translateY(${virtualItem.start}px)`,
}}
>
{renderItem(items[virtualItem.index], virtualItem.index)}
</div>
))}
</div>
</div>
)
}TanStack Virtual, top konumlandırması yerine transform: translateY() kullanır. Bu, düzen yeniden hesaplaması yerine GPU birleştirmesini tetikler ve karmaşık öğe render işleminde bile kaydırmayı 60fps'de tutar.
Otomatik Ölçümle Dinamik Öğe Yükseklikleri
Sabit yükseklikli öğeler sanallaştırma matematiğini basitleştirir, ancak gerçek uygulamalar genellikle değişken yükseklikler gerektirir. TanStack Virtual, ResizeObserver kullanarak öğeleri otomatik olarak ölçer:
import { useVirtualizer } from '@tanstack/react-virtual'
import { useRef, useCallback } from 'react'
interface Message {
id: string
text: string
timestamp: number
}
export function ChatVirtualList({ messages }: { messages: Message[] }) {
const parentRef = useRef<HTMLDivElement>(null)
const virtualizer = useVirtualizer({
count: messages.length,
getScrollElement: () => parentRef.current,
estimateSize: useCallback(() => 72, []), // Başlangıç tahmini
measureElement: (element) => element.getBoundingClientRect().height,
})
return (
<div ref={parentRef} className="h-full overflow-auto">
<div
style={{
height: `${virtualizer.getTotalSize()}px`,
position: 'relative',
}}
>
{virtualizer.getVirtualItems().map((virtualItem) => (
<div
key={virtualItem.key}
data-index={virtualItem.index}
ref={virtualizer.measureElement}
style={{
position: 'absolute',
top: 0,
left: 0,
width: '100%',
transform: `translateY(${virtualItem.start}px)`,
}}
>
<ChatBubble message={messages[virtualItem.index]} />
</div>
))}
</div>
</div>
)
}measureElement callback'i her render edilen elemanı alır ve ölçülen yüksekliğini döndürür. TanStack Virtual bu ölçümleri önbelleğe alır ve yalnızca ResizeObserver değişiklikleri algıladığında yeniden ölçer.
React Virtuoso: Kutudan Çıktığı Gibi Üretime Hazır
React Virtuoso (sürüm 4.18, Eylül 2026) uç durumları otomatik olarak işleyen daha üst düzey bir API sunar. Haftalık 2,8 milyon npm indirmesiyle, minimum yapılandırma isteyen ekipler için varsayılan tercih haline geldi.
import { Virtuoso } from 'react-virtuoso'
interface Product {
id: string
name: string
price: number
description: string
}
export function ProductList({ products }: { products: Product[] }) {
return (
<Virtuoso
data={products}
itemContent={(index, product) => (
<div className="p-4 border-b border-gray-200">
<h3 className="font-semibold">{product.name}</h3>
<p className="text-sm text-gray-600">{product.description}</p>
<span className="text-lg font-bold">${product.price}</span>
</div>
)}
style={{ height: '100%' }}
/>
)
}Virtuoso, ek yapılandırma olmadan değişken yükseklikleri, gruplandırılmış öğeleri ve ters kaydırmayı işler. Kaydırma konumunu korurken öğe eklemeyi gerektiren sohbet uygulamaları veya log görüntüleyiciler için sorunsuz çalışır:
import { Virtuoso, VirtuosoHandle } from 'react-virtuoso'
import { useRef, useState, useCallback } from 'react'
export function ChatWithPrepend() {
const virtuosoRef = useRef<VirtuosoHandle>(null)
const [messages, setMessages] = useState<Message[]>(initialMessages)
const prependMessages = useCallback((newMessages: Message[]) => {
setMessages((prev) => [...newMessages, ...prev])
}, [])
return (
<Virtuoso
ref={virtuosoRef}
data={messages}
firstItemIndex={10000 - messages.length} // Sanal indeks ofseti
initialTopMostItemIndex={messages.length - 1}
followOutput="smooth" // Yeni mesajlara otomatik kaydır
startReached={() => loadOlderMessages().then(prependMessages)}
itemContent={(index, message) => <ChatBubble message={message} />}
/>
)
}firstItemIndex özelliği çift yönlü sonsuz kaydırmayı etkinleştirir. Virtuoso, DOM konumlarını kaydırmak yerine sanal indeksleri ayarlayarak başa ekleme sırasında kaydırma konumunu korur.
Node.js / NestJS mülakatlarında başarılı olmaya hazır mısın?
İnteraktif simülatörler, flashcards ve teknik testlerle pratik yap.
Performans Karşılaştırması: TanStack vs Virtuoso vs react-window
100.000 öğeyle 2026 orta sınıf bir dizüstü bilgisayarda (M3 MacBook Air) benchmark sonuçları:
| Kütüphane | İlk Mount | Ortaya Kaydır | Bellek Kullanımı |
|---|---|---|---|
| TanStack Virtual 3.13 | 4,5ms | 12ms | 2,1MB |
| react-virtuoso 4.18 | 6,2ms | 15ms | 3,4MB |
| react-window 1.8 | 3,8ms | 8ms | 1,8MB |
React-window sabit yükseklikli öğeler için en hızlı olmaya devam ediyor ancak dinamik ölçümden yoksun. TanStack Virtual performans ve özellikler arasında en iyi dengeyi sunuyor. Virtuoso, otomatik uç durum işleme ile geliştirici deneyimini önceliklendirir.
Memoization ile Öğe Render Optimizasyonu
Sanallaştırma DOM düğümlerini azaltır ancak öğeler içindeki pahalı yeniden render'ları önleyemez. React.memo vazgeçilmez hale gelir:
import { memo } from 'react'
interface ListItemProps {
item: Product
onSelect: (id: string) => void
}
export const ListItem = memo(function ListItem({ item, onSelect }: ListItemProps) {
return (
<div
className="p-4 hover:bg-gray-50 cursor-pointer"
onClick={() => onSelect(item.id)}
>
<h3>{item.name}</h3>
<p>{item.description}</p>
</div>
)
}, (prevProps, nextProps) => {
// Özel karşılaştırma: yalnızca öğe verileri değiştiğinde yeniden render et
return prevProps.item.id === nextProps.item.id &&
prevProps.item.name === nextProps.item.name
})Özel karşılaştırma fonksiyonu, yalnızca referans değiştiğinde ancak içerik aynı kaldığında yeniden render'ları önler. Bu, yeni nesne referansları döndüren veri alma paternlerinde yaygındır.
Kaydırma Konumu Geri Yüklemeyi Yönetme
Kullanıcılar, uzaklaşıp geri döndüklerinde kaydırma konumunun korunmasını bekler. Virtualizer durumuyla birleştirilmiş History API bunu mümkün kılar:
import { useEffect, useRef } from 'react'
import { Virtualizer } from '@tanstack/react-virtual'
export function useScrollRestoration(
virtualizer: Virtualizer<HTMLDivElement, Element>,
storageKey: string
) {
const restoredRef = useRef(false)
// Mount sırasında geri yükle
useEffect(() => {
if (restoredRef.current) return
const saved = sessionStorage.getItem(storageKey)
if (saved) {
const { offset } = JSON.parse(saved)
virtualizer.scrollToOffset(offset, { align: 'start' })
}
restoredRef.current = true
}, [virtualizer, storageKey])
// Unmount öncesi kaydet
useEffect(() => {
return () => {
const offset = virtualizer.scrollOffset
sessionStorage.setItem(storageKey, JSON.stringify({ offset }))
}
}, [virtualizer, storageKey])
}Bu pattern, kaydırma ofsetini sessionStorage'da saklar, sayfa navigasyonunda hayatta kalır ancak sekme kapandığında temizlenir.
Mülakat Konuları: İşe Alımcıların Liste Sanallaştırması Hakkında Sorduğu Sorular
Teknik mülakatlar giderek artan şekilde sanallaştırma bilgisini kapsar. Yaygın sorular ve güçlü cevaplar:
S: Tarayıcılar neden 100k DOM düğümünü verimli şekilde işleyemiyor? Render pipeline, stil hesaplama ve düzen sırasında her düğümü işler. Düğüm nesnelerinden, hesaplanmış stillerden ve düzen ağaçlarından gelen bellek baskısı birikir. 10k düğümün ötesinde, garbage collection duraklamaları kaydırma sırasında fark edilir hale gelir.
S: Windowing vs recycling'i açıklayın. Windowing yalnızca görünür öğeleri render eder. Recycling, öğeler görünümden çıktığında mevcut DOM düğümlerini yeni veriler için yeniden kullanır. TanStack Virtual ve react-virtuoso windowing kullanır. Yerel mobil framework'ler (iOS UITableView, Android RecyclerView) recycling kullanır.
S: Bir resim grid'ini nasıl sanallaştırırsınız?
TanStack Virtual'ın useVirtualizer'ını hem satır hem sütun boyutlarıyla kullanın. Her iki eksen için estimateSize uygulayın. IntersectionObserver ile lazy loading ekleyin. Viewport kenarına yakın öğeler için CSS content-visibility: auto düşünün.
Frontend performans konularında daha fazla mülakat hazırlığı için, ilgili optimizasyon paternlerini kapsayan React Testing mülakat modülüne bakın.
Yaygın Tuzaklar ve Bunlardan Nasıl Kaçınılır
Yanlış konteyner yüksekliği: Sanallaştırma, sabit yükseklikte bir kaydırma konteyneri gerektirir. height: auto kullanmak veya içerik yüksekliğine güvenmek ölçüm hesaplamalarını bozar.
Eksik key'ler: React, geri dönüştürülen elemanlar için kararlı key'ler gerektirir. Dizi indeksleri kullanmak, öğeler yeniden sıralandığında durum hatalarına neden olur.
Çok düşük overscan: Sıfır overscan, hızlı kaydırma sırasında görünür boş alanlara neden olur. 3-10 arası değerler performans ve görsel pürüzsüzlük arasında denge kurar.
Memoize edilmemiş callback'ler: Öğe prop'ları olarak inline fonksiyon geçirmek her kaydırmada yeniden render'lara neden olur. Handler'ları useCallback veya bileşen kapsamına çıkarın.
JavaScript Liste Sanallaştırması için Temel Çıkarımlar
- Veri boyutu değil, DOM düğüm sayısı kaydırma performansını belirler. Sanallaştırma, liste uzunluğundan bağımsız olarak düğümleri sınırlar.
- TanStack Virtual 3.13, framework esnekliği ve maksimum kontrol gerektiren uygulamalar için uygundur. Soğuk mount performansı önceki sürümlere göre %35 iyileşti.
- react-virtuoso 4.18, minimum kodla dinamik yükseklikleri, gruplamayı ve çift yönlü kaydırmayı işler. Haftalık 2,8M indirme, üretim kararlılığını yansıtır.
- react-window, paket boyutunun önemli olduğu sabit yükseklik senaryoları için hala geçerli, ancak aktif geliştirme durdu.
- Özel karşılaştırma fonksiyonlarıyla liste öğelerini memoize edin. Veri kaynakları yeni nesneler oluşturduğunda referans eşitliği kontrolleri başarısız olur.
- Navigasyonlar arasında geri yükleme için kaydırma ofsetini sessionStorage'da saklayın. Virtualizer ofseti doğrudan piksel konumuna eşlenir.
Pratik yapmaya başla!
Mülakat simülatörleri ve teknik testlerle bilgini test et.
Node.js / NestJS kodundaki hatayı bulabilir misin?
Gerçek bir kod parçası, gizli bir hata, günde bir deneme. Denemek için hesap gerekmez.

Yazan:
Anthony Fillion-MailletSharpSkill kurucusu
10 yılı aşkın süredir fullstack geliştirici. SharpSkill’i yönetiyor ve burada yayımlanan her şeyden sorumlu.
7 Eylül 2026 tarihinde güncellendi
Paylaş
İlgili makaleler

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.

2026'da NestJS ve Redis: Önbellekleme, Oturumlar ve Mülakat Soruları
NestJS'te Redis entegrasyonu için kapsamlı rehber. Cache-manager, oturum yönetimi ve invalidasyon stratejileri.

2026'da NestJS ve MongoDB: Mongoose, Aggregation'lar ve Mülakat Soruları
NestJS ile MongoDB ve Mongoose 9 konusunda uzmanlaşın. Şema tasarım kalıplarını, aggregation pipeline'larını öğrenin ve pratik örneklerle teknik mülakatlarına hazırlanın.