Virtualisierte Listen mit Text-Messung optimieren
Wende Text-Messung an, um nur sichtbare Zeilen in großen Listen zu rendern, indem du vorab Zeilenhöhen berechnest statt live zu messen.
Originalvideo ansehen: He just crawled through hell to fix the browser…3 Schritte
1
Alle Zeilenhöhen vorab berechnen
Berechne die Höhe jedes Text-Elements einmalig, bevor das Rendering beginnt
const messages = [/* 10.000 Nachrichten */];
const lineHeights = messages.map(msg => {
const segments = pretext.prepare(msg.content, { font: '14px Arial' });
return pretext.layout(segments, { width: 400 }).height;
});Tipp: Speichere diese Höhen im State oder einer Map für schnelle Lookups
Warnung: Neu-Berechnung nur bei Font- oder Container-Änderungen
2
Scroll-Position zu sichtbarem Range mappen
Nutze Höhen, um zu berechnen, welche Zeilen sichtbar sind, basierend auf Scroll-Position
function calculateVisibleRange(lineHeights, scrollTop, viewportHeight) {
let accumulatedHeight = 0;
let startIndex = 0;
let endIndex = 0;
for (let i = 0; i < lineHeights.length; i++) {
if (accumulatedHeight + lineHeights[i] > scrollTop) {
startIndex = i;
break;
}
accumulatedHeight += lineHeights[i];
}
accumulatedHeight = 0;
for (let i = 0; i <= startIndex; i++) {
accumulatedHeight += lineHeights[i];
}
while (accumulatedHeight < scrollTop + viewportHeight && endIndex < lineHeights.length) {
accumulatedHeight += lineHeights[endIndex];
endIndex++;
}
return { startIndex, endIndex };
}Tipp: Verwende Binärsuche für O(log n) statt O(n) Komplexität
Warnung: Off-by-one Fehler sind häufig; teste mit Boundary-Cases
3
Nur sichtbare Items rendern
Rendere nur die Nachrichten zwischen startIndex und endIndex
const { startIndex, endIndex } = calculateVisibleRange(lineHeights, scrollTop, viewportHeight);
const visibleItems = messages.slice(startIndex, endIndex);
return (
<div onScroll={(e) => setScrollTop(e.target.scrollTop)}>
{visibleItems.map(item => <Message key={item.id} {...item} />)}
</div>
);Tipp: Rendere ein paar Extra-Items oberhalb/unterhalb für smootheres Scrollen
Warnung: ScrollListener sollte gedrosselt werden (requestAnimationFrame)