언어·프레임워크/React.js
[React.js] React에서 대용량 데이터 효율적으로 렌더링하기: useVirtualizer
DandyNow
2025. 2. 4. 14:37
728x90
반응형
1. 대규모 데이터 렌더링의 도전 과제
현재 진행 중인 프로젝트에서 약 5000개의 객체를 가지고 있는 배열을 다루게 되었다. 이 배열 데이터를 테이블로 렌더링하였는데 역시나 성능 이슈가 발생했다. 이번 케이스와 같이 웹 애플리케이션에서 수천 또는 수만 개의 데이터 항목을 한 번에 렌더링하면-스크롤-성능이 크게 저하된다. 모든 항목을 DOM에 동시에 렌더링하면 브라우저 메모리 사용량이 급증하기 때문이다.
2. 가상화(Virtualization)란?
이 이슈를 해결하기 위해 가상화 기술을 적용하였다. 가상화는 현재 뷰포트에 보이는 항목만 실제로 렌더링하고, 스크롤에 따라 동적으로 항목을 로드하는 기술이다. 이를 통해 대용량 데이터를 매우 효율적으로 처리할 수 있다.
3. @tanstack/react-virtual의 useVirtualizer 소개
가상화 기술을 적용하기 위해 @tanstack/react-virtual
라이브러리의 useVirtualizer
훅을 사용하였다. React에서 가장 강력하고 유연한 가상화 솔루션 중 하나이다.
주요 특징
- 고성능 가상 렌더링
- 스크롤 위치 기반 동적 항목 렌더링
- 오버스캔(Overscan) 지원
- 다양한 리스트/그리드 레이아웃 지원
4. 실제 구현 예시
const rowVirtualizer = useVirtualizer({
count: visibleData.length, // 전체 데이터 길이
getScrollElement: () => parentRef.current, // 스크롤 컨테이너
estimateSize: () => 30, // 각 행의 예상 높이
overscan: 10 // 추가로 미리 렌더링할 항목 수
});
핵심 구현 전략
- 동적 높이 관리
estimateSize
로 각 행의 예상 높이 설정- 정확한 스크롤 계산을 위해 중요
- 위치 조정
- CSS Transform을 사용해 각 행의 정확한 위치 지정
- 하드웨어 가속을 활용한 부드러운 스크롤 성능
transform: `translateY(${virtualRow.start}px)`
- 오버스캔(Overscan) 활용
- 현재 뷰포트 주변의 추가 항목 미리 렌더링
- 스크롤 경험 개선
5. 성능 최적화 팁
- 고정된 행 높이 사용
table-layout: fixed
적용- 텍스트 오버플로우 처리
- 최소한의 DOM 요소 사용
6. 주의할 점
- 너무 많은 오버스캔은 성능 저하 원인
- 나의 경우 처음부터
overscan: 10
을 적용하였고 변경의 필요성을 느끼지 못하였다.
- 나의 경우 처음부터
- 정확한 행 높이 예측 중요
- estimateSize와 행을 이루는 요소의 스타일(height)의 값을 잘 맞춰야 한다.
- 가상화가 적용된 테이블을 스크롤링할 때 각 행(tr)의 높이가 일정하게 유지되지 않고 점점 커지는 현상이 발생하였기에
tr
태그에 다음과 같은 스타일을 추가하였다.
<tr
key={item.mac}
style={{
position: 'absolute',
top: 0,
left: 0,
width: '100%',
height: '30px',
transform: `translateY(${virtualRow.start}px)`,
display: 'table',
tableLayout: 'fixed',
}}
>
- 인라인 스타일 사용
- CSS class로 스타일을 적용하는 대신 인라인 스타일을 사용한다. 그 이유는 가상화된 테이블의 특성상 일반적인 CSS 규칙이 제대로 적용되지 않을 수 있기 때문이다.
- 페이지네이션 병행 고려
- 대용량 데이터의 경우 페이지네이션과 병행을 고려한다.
- 나의 경우 무한 스크롤을 함께 적용하였다.
728x90
반응형