한 줄 요약 항목이 1만 개여도 화면에 보이는 ~15개만 진짜로 그리고, 스크롤할 때 그 몇 개를 재활용해 위치만 옮기는 기법입니다.
이럴 때 필요해요
채팅 메시지, 검색 결과, 표처럼 항목이 수천~수만 개로 늘어나는 화면을 만들 때입니다. 1만 개를 그냥 다 그리면 브라우저가 DOM 노드(화면을 구성하는 요소 하나하나)를 1만 개나 만들어야 해서 스크롤이 뚝뚝 끊기고 메모리도 폭발합니다. 가상 스크롤(virtual scroll, 일명 windowing)은 "어차피 한 번에 보이는 건 십몇 개뿐인데 왜 1만 개를 다 그리지?"라는 발상에서 출발합니다.
어떻게 동작하나
행 높이를 고정(예 56px)으로 정해두면 스크롤한 거리(scrollTop)만 보고 "지금 맨 위에 걸친 게 몇 번째 항목인지"를 나눗셈으로 바로 알 수 있습니다.
빈 spacer div의 높이를 전체 개수 행 높이로 만들어 둡니다 실제로는 몇 개만 그려도 스크롤바는 "진짜 1만 개짜리" 길이로 보입니다.
보이는 구간의 항목만 잘라 그리고, 그 묶음을 translateY로 제자리까지 한 번에 밀어 둡니다. overscan(여유분, 위아래로 몇 개 더 그려두는 것)을 두어 빠르게 스크롤해도 빈칸이 안 보이게 합니다.
핵심은 이거예요
화면 카운터에 "실제 렌더된 DOM 행"이 전체 개수와 상관없이 항상 ~15개로 유지되는 것 이것만 이해하면 됩니다. 나머지는 그 15개의 위치를 계산해 옮기는 일일 뿐입니다.
놓치기 쉬운 것
행 높이가 들쭉날쭉하면 이 단순 계산이 깨집니다(가변 높이는 측정누적합이 추가로 필요).
overscan이 0이면 빠른 스크롤 시 잠깐 빈칸이 보입니다.
spacer 높이를 안 만들면 스크롤바가 짧아져 끝까지 스크롤이 안 됩니다.
이런 곳에 써요
슬랙디스코드 같은 긴 메시지 타임라인
수천 행짜리 관리자 테이블, 무한 스크롤 피드