Schnelle JavaScript ListView 2026: Windowing, Virtualisierung und Performance-Optimierung
Erfahren Sie, wie man mit Windowing und Virtualisierung performante JavaScript ListViews erstellt. React Virtualized, TanStack Virtual und weitere Techniken für 2026.

Moderne Webanwendungen müssen häufig tausende oder sogar hunderttausende von Datensätzen in Listen darstellen. Ob es sich um E-Commerce-Produktkataloge, Social-Media-Feeds oder Admin-Dashboards handelt – die Performance einer ListView kann das Benutzererlebnis entscheidend beeinflussen. Dieser Artikel untersucht die neuesten Techniken zur Optimierung von JavaScript ListViews im Jahr 2026.
Virtualisierung kann den Speicherverbrauch bei Listen mit 10.000+ Elementen um bis zu 95% reduzieren und gleichzeitig eine flüssige Scroll-Performance gewährleisten.
Das Problem mit großen Listen
Wenn eine Anwendung eine Liste mit zehntausend Elementen rendert, erzeugt der Browser für jedes Element DOM-Knoten. Dies führt zu erheblichen Problemen:
- Hoher Speicherverbrauch: Jeder DOM-Knoten benötigt Speicher
- Langsame initiale Renderzeit: Das Erstellen tausender Elemente dauert lange
- Träge Scroll-Performance: Der Browser muss alle Elemente verwalten
- Layout-Thrashing: Häufige Neuberechnungen des Layouts
// Naive Implementierung - NICHT empfohlen für große Listen
function NaiveList({ items }: { items: Item[] }) {
return (
<div className="list-container">
{items.map((item) => (
<div key={item.id} className="list-item">
<h3>{item.title}</h3>
<p>{item.description}</p>
</div>
))}
</div>
);
}Windowing als Lösungsansatz
Windowing, auch als "virtuelles Scrollen" bekannt, ist eine Technik, bei der nur die sichtbaren Elemente sowie ein kleiner Puffer darüber und darunter gerendert werden. Die restlichen Elemente werden erst bei Bedarf erstellt.
import { useVirtualizer } from '@tanstack/react-virtual';
function VirtualizedList({ items }: { items: Item[] }) {
const parentRef = useRef<HTMLDivElement>(null);
const virtualizer = useVirtualizer({
count: items.length,
getScrollElement: () => parentRef.current,
estimateSize: () => 80,
overscan: 5,
});
return (
<div ref={parentRef} className="h-[600px] 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)`,
}}
>
<ListItem item={items[virtualItem.index]} />
</div>
))}
</div>
</div>
);
}TanStack Virtual: Der moderne Standard
TanStack Virtual (ehemals React Virtual) hat sich 2026 als die führende Lösung für Virtualisierung in React-Anwendungen etabliert. Die Bibliothek bietet Framework-agnostische Kernfunktionen mit spezifischen Adaptern für React, Vue, Solid und weitere Frameworks.
import { useVirtualizer, VirtualizerOptions } from '@tanstack/react-virtual';
interface ListProps<T> {
items: T[];
renderItem: (item: T, index: number) => React.ReactNode;
itemHeight?: number | ((index: number) => number);
overscan?: number;
}
function HighPerformanceList<T extends { id: string }>({
items,
renderItem,
itemHeight = 80,
overscan = 10
}: ListProps<T>) {
const parentRef = useRef<HTMLDivElement>(null);
const virtualizer = useVirtualizer({
count: items.length,
getScrollElement: () => parentRef.current,
estimateSize: typeof itemHeight === 'function'
? itemHeight
: () => itemHeight,
overscan,
measureElement: (element) => element.getBoundingClientRect().height,
});
const virtualItems = virtualizer.getVirtualItems();
return (
<div
ref={parentRef}
className="h-full overflow-auto will-change-transform"
>
<div
className="relative w-full"
style={{ height: `${virtualizer.getTotalSize()}px` }}
>
{virtualItems.map((virtualItem) => (
<div
key={items[virtualItem.index].id}
ref={virtualizer.measureElement}
data-index={virtualItem.index}
className="absolute top-0 left-0 w-full"
style={{
transform: `translateY(${virtualItem.start}px)`,
}}
>
{renderItem(items[virtualItem.index], virtualItem.index)}
</div>
))}
</div>
</div>
);
}Dynamische Elementhöhen
Eine der größten Herausforderungen bei der Virtualisierung sind Listen mit Elementen unterschiedlicher Höhe. TanStack Virtual bietet hierfür die measureElement-Funktion, die die tatsächliche Größe jedes Elements misst.
function DynamicHeightList({ items }: { items: Post[] }) {
const parentRef = useRef<HTMLDivElement>(null);
const measurementsCache = useRef<Map<string, number>>(new Map());
const virtualizer = useVirtualizer({
count: items.length,
getScrollElement: () => parentRef.current,
estimateSize: (index) => {
const cached = measurementsCache.current.get(items[index].id);
if (cached) return cached;
// Schätzung basierend auf Inhaltslänge
const contentLength = items[index].content.length;
return Math.max(100, Math.min(400, contentLength * 0.5));
},
measureElement: (element) => {
const height = element.getBoundingClientRect().height;
const id = element.getAttribute('data-id');
if (id) {
measurementsCache.current.set(id, height);
}
return height;
},
overscan: 5,
});
return (
<div ref={parentRef} className="h-screen overflow-auto">
<div
style={{
height: `${virtualizer.getTotalSize()}px`,
position: 'relative',
}}
>
{virtualizer.getVirtualItems().map((virtualItem) => {
const item = items[virtualItem.index];
return (
<div
key={item.id}
ref={virtualizer.measureElement}
data-index={virtualItem.index}
data-id={item.id}
style={{
position: 'absolute',
top: 0,
left: 0,
width: '100%',
transform: `translateY(${virtualItem.start}px)`,
}}
>
<PostCard post={item} />
</div>
);
})}
</div>
</div>
);
}Infinite Scrolling mit Virtualisierung
Die Kombination von Virtualisierung mit Infinite Scrolling ermöglicht das Laden und Anzeigen unbegrenzter Datenmengen bei optimaler Performance.
import { useInfiniteQuery } from '@tanstack/react-query';
import { useVirtualizer } from '@tanstack/react-virtual';
function InfiniteVirtualList() {
const parentRef = useRef<HTMLDivElement>(null);
const {
data,
fetchNextPage,
hasNextPage,
isFetchingNextPage,
} = useInfiniteQuery({
queryKey: ['items'],
queryFn: ({ pageParam = 0 }) => fetchItems(pageParam),
getNextPageParam: (lastPage) => lastPage.nextCursor,
initialPageParam: 0,
});
const allItems = useMemo(
() => data?.pages.flatMap((page) => page.items) ?? [],
[data]
);
const virtualizer = useVirtualizer({
count: hasNextPage ? allItems.length + 1 : allItems.length,
getScrollElement: () => parentRef.current,
estimateSize: () => 80,
overscan: 10,
});
const virtualItems = virtualizer.getVirtualItems();
useEffect(() => {
const lastItem = virtualItems[virtualItems.length - 1];
if (!lastItem) return;
if (
lastItem.index >= allItems.length - 1 &&
hasNextPage &&
!isFetchingNextPage
) {
fetchNextPage();
}
}, [virtualItems, allItems.length, hasNextPage, isFetchingNextPage, fetchNextPage]);
return (
<div ref={parentRef} className="h-[600px] overflow-auto">
<div
style={{
height: `${virtualizer.getTotalSize()}px`,
position: 'relative',
}}
>
{virtualItems.map((virtualItem) => {
const isLoader = virtualItem.index >= allItems.length;
return (
<div
key={virtualItem.key}
style={{
position: 'absolute',
top: 0,
left: 0,
width: '100%',
height: `${virtualItem.size}px`,
transform: `translateY(${virtualItem.start}px)`,
}}
>
{isLoader ? (
<div className="flex items-center justify-center h-full">
<Spinner />
</div>
) : (
<ItemRow item={allItems[virtualItem.index]} />
)}
</div>
);
})}
</div>
</div>
);
}Performance-Optimierungen
Neben der Virtualisierung gibt es weitere Techniken zur Leistungsverbesserung von ListViews.
Memoization von Listenelementen
const MemoizedListItem = memo(
function ListItem({ item }: { item: Item }) {
return (
<div className="p-4 border-b border-gray-200">
<h3 className="font-medium">{item.title}</h3>
<p className="text-gray-600">{item.description}</p>
</div>
);
},
(prevProps, nextProps) => prevProps.item.id === nextProps.item.id
);CSS-Optimierungen
.list-container {
contain: strict;
will-change: transform;
}
.list-item {
contain: layout style paint;
content-visibility: auto;
contain-intrinsic-size: 0 80px;
}Content-Visibility für nicht-virtualisierte Listen
function OptimizedStaticList({ items }: { items: Item[] }) {
return (
<div className="list-container">
{items.map((item) => (
<div
key={item.id}
className="list-item"
style={{
contentVisibility: 'auto',
containIntrinsicSize: '0 80px',
}}
>
<ListItemContent item={item} />
</div>
))}
</div>
);
}Horizontale Virtualisierung und Grids
TanStack Virtual unterstützt auch horizontale Virtualisierung und zweidimensionale Grids.
function VirtualizedGrid({ items, columns = 4 }: { items: Item[]; columns?: number }) {
const parentRef = useRef<HTMLDivElement>(null);
const rows = Math.ceil(items.length / columns);
const rowVirtualizer = useVirtualizer({
count: rows,
getScrollElement: () => parentRef.current,
estimateSize: () => 200,
overscan: 2,
});
const columnVirtualizer = useVirtualizer({
horizontal: true,
count: columns,
getScrollElement: () => parentRef.current,
estimateSize: () => 250,
overscan: 1,
});
return (
<div ref={parentRef} className="h-[600px] overflow-auto">
<div
style={{
height: `${rowVirtualizer.getTotalSize()}px`,
width: `${columnVirtualizer.getTotalSize()}px`,
position: 'relative',
}}
>
{rowVirtualizer.getVirtualItems().map((virtualRow) => (
<Fragment key={virtualRow.key}>
{columnVirtualizer.getVirtualItems().map((virtualColumn) => {
const itemIndex = virtualRow.index * columns + virtualColumn.index;
if (itemIndex >= items.length) return null;
return (
<div
key={virtualColumn.key}
style={{
position: 'absolute',
top: 0,
left: 0,
width: `${virtualColumn.size}px`,
height: `${virtualRow.size}px`,
transform: `translateX(${virtualColumn.start}px) translateY(${virtualRow.start}px)`,
}}
>
<GridItem item={items[itemIndex]} />
</div>
);
})}
</Fragment>
))}
</div>
</div>
);
}Bereit für deine Node.js / NestJS-Interviews?
Übe mit unseren interaktiven Simulatoren, Flashcards und technischen Tests.
Debugging und Monitoring
Um Performance-Probleme zu identifizieren, können verschiedene Metriken überwacht werden.
function useVirtualListMetrics(virtualizer: Virtualizer<HTMLDivElement, Element>) {
const [metrics, setMetrics] = useState({
renderedCount: 0,
totalCount: 0,
scrollOffset: 0,
visibleRange: { start: 0, end: 0 },
});
useEffect(() => {
const updateMetrics = () => {
const virtualItems = virtualizer.getVirtualItems();
setMetrics({
renderedCount: virtualItems.length,
totalCount: virtualizer.options.count,
scrollOffset: virtualizer.scrollOffset ?? 0,
visibleRange: {
start: virtualItems[0]?.index ?? 0,
end: virtualItems[virtualItems.length - 1]?.index ?? 0,
},
});
};
updateMetrics();
const unsubscribe = virtualizer.scrollElement?.addEventListener(
'scroll',
updateMetrics
);
return () => {
virtualizer.scrollElement?.removeEventListener('scroll', updateMetrics as any);
};
}, [virtualizer]);
return metrics;
}Fazit
Die Implementierung performanter ListViews in JavaScript erfordert 2026 ein gutes Verständnis von Virtualisierungstechniken. TanStack Virtual bietet eine ausgereifte, typsichere Lösung, die sich nahtlos in moderne React-Anwendungen integriert. Durch die Kombination von Windowing mit Memoization, CSS-Containment und intelligenten Ladestrategien lassen sich selbst Listen mit hunderttausenden Elementen flüssig darstellen. Die vorgestellten Techniken sind essentiell für jede datenintensive Webanwendung und sollten zum Standardrepertoire moderner Frontend-Entwicklung gehören.
Findest du den Bug in Node.js / NestJS?
Ein echter Codeausschnitt, ein versteckter Bug, ein Versuch pro Tag. Zum Ausprobieren ohne Konto.

Geschrieben von
Anthony Fillion-MailletGründer von SharpSkill
Seit über 10 Jahren Fullstack-Entwickler. Er leitet SharpSkill und verantwortet alles, was hier erscheint.
Aktualisiert am 15. September 2026
Teilen
Verwandte Artikel

NestJS und Redis in 2026: Caching, Sessions und Technische Interviewfragen
NestJS Redis-Integration mit @nestjs/cache-manager, Session-Verwaltung mit connect-redis und häufige Interviewfragen für Node.js-Backend-Entwickler.

High Performance JavaScript ListView 2026: Virtualisierung und Optimierungstechniken
Erfahren Sie, wie Sie mit JavaScript List-Virtualisierung und React Virtualized hochperformante ListViews entwickeln. Deep-Dive in Rendering-Optimierung für große Datenmengen.

NestJS und MongoDB 2026: Mongoose-Integration, Aggregationen und Interview-Fragen
Praxisleitfaden für NestJS 12 mit MongoDB und Mongoose 9: Schema-Design, Aggregation-Pipelines, Transaktionen und technische Interview-Fragen für Backend-Entwickler.