React에서 가상 스크롤링 구현하기 – 개념부터 구현까지 완벽 마스터

1. 알고리즘 소개 및 개념

React에서 가상 스크롤링 구현하기는 대용량 데이터를 효율적으로 렌더링하기 위한 필수 기술입니다. 가상 스크롤링(Virtual Scrolling)은 수천, 수만 개의 리스트 아이템을 렌더링할 때 실제로 화면에 보이는 요소만 DOM에 마운트하는 최적화 기법입니다. 전체 데이터를 한 번에 렌더링하면 브라우저 성능이 급격히 저하되지만, 가상 스크롤링을 사용하면 뷰포트에 보이는 아이템만 렌더링하여 초기 로딩 시간을 단축하고 메모리 사용량을 크게 줄일 수 있습니다. 이 기술은 무한 스크롤, 대시보드, 데이터 테이블 등 다양한 실전 프로젝트에서 필수적으로 활용됩니다.

2. 동작 원리 상세 설명

가상 스크롤링의 핵심 원리는 ‘윈도잉(Windowing)’ 개념입니다. 전체 10,000개의 아이템이 있더라도 사용자의 뷰포트에는 약 10-20개만 보이므로, 실제로 렌더링하는 것은 현재 보이는 영역과 상하 버퍼 영역의 아이템만으로 제한합니다. 스크롤 이벤트가 발생하면 현재 스크롤 위치를 계산하여 어떤 아이템들이 보여야 하는지 동적으로 결정합니다. 예를 들어, 각 아이템의 높이가 50px이고 스크롤 위치가 1000px이라면 인덱스 20번 근처의 아이템들을 렌더링합니다. 컨테이너의 전체 높이는 CSS로 설정하여 스크롤바가 정확한 비율을 유지하도록 하고, 실제 아이템들은 absolute positioning을 사용해 올바른 위치에 배치합니다. 이를 통해 DOM 노드 수를 최소화하면서도 사용자에게는 전체 리스트가 있는 것처럼 자연스러운 스크롤 경험을 제공합니다.

3. 시간/공간 복잡도 분석

시간 복잡도: 가상 스크롤링의 초기 렌더링 시간 복잡도는 O(V)입니다. 여기서 V는 뷰포트에 보이는 아이템 수로, 전체 데이터 크기 N과 무관하게 일정합니다. 스크롤 이벤트 처리는 O(1)로, 현재 위치 계산과 인덱스 범위 결정만 수행합니다. 일반적인 리스트 렌더링의 O(N) 복잡도와 비교하면 극적인 성능 향상을 보입니다. 공간 복잡도: 메모리 사용량도 O(V)로 제한됩니다. 전체 데이터는 메모리에 유지하지만, 실제 DOM 노드는 뷰포트에 보이는 만큼만 생성되므로 N=100,000일 때도 V=20 정도의 DOM 노드만 유지합니다. 이는 브라우저의 레이아웃 계산과 페인팅 비용을 획기적으로 줄여줍니다. 다만 전체 데이터를 메모리에 유지해야 하므로 데이터 크기 자체에 대한 O(N) 공간은 필요합니다.

4. 단계별 구현 과정

Step 1: 기본 상태 및 참조 설정

React에서 가상 스크롤링 구현하기의 첫 단계는 필요한 상태와 참조를 설정하는 것입니다. 컨테이너의 높이, 아이템 높이, 현재 스크롤 위치 등을 관리해야 합니다.

import React, { useState, useRef, useEffect } from 'react';

function VirtualScroll({ items, itemHeight = 50, containerHeight = 600 }) {
  const [scrollTop, setScrollTop] = useState(0);
  const containerRef = useRef(null);
  
  // 뷰포트에 보일 아이템 범위 계산
  const visibleCount = Math.ceil(containerHeight / itemHeight);
  const totalHeight = items.length * itemHeight;
  
  // 버퍼를 포함한 시작/끝 인덱스 계산
  const startIndex = Math.max(0, Math.floor(scrollTop / itemHeight) - 3);
  const endIndex = Math.min(items.length, startIndex + visibleCount + 6);
  
  const visibleItems = items.slice(startIndex, endIndex);
  
  return (
    
setScrollTop(e.target.scrollTop)} >
{visibleItems.map((item, index) => { const actualIndex = startIndex + index; return (
{item.content}
); })}
); }

Step 2: 동적 높이 처리

모든 아이템의 높이가 동일하지 않은 경우를 위한 고급 구현입니다. 각 아이템의 높이를 측정하고 누적 높이를 계산합니다.

function DynamicVirtualScroll({ items, estimatedHeight = 50, containerHeight = 600 }) {
  const [scrollTop, setScrollTop] = useState(0);
  const [heights, setHeights] = useState(new Map());
  const itemRefs = useRef(new Map());
  
  // 각 아이템의 실제 높이 측정
  useEffect(() => {
    const newHeights = new Map();
    itemRefs.current.forEach((element, index) => {
      if (element) {
        newHeights.set(index, element.getBoundingClientRect().height);
      }
    });
    setHeights(newHeights);
  }, [items]);
  
  // 누적 높이 계산으로 각 아이템의 위치 결정
  const getItemOffset = (index) => {
    let offset = 0;
    for (let i = 0; i < index; i++) {
      offset += heights.get(i) || estimatedHeight;
    }
    return offset;
  };
  
  const getTotalHeight = () => {
    return items.reduce((sum, _, index) => 
      sum + (heights.get(index) || estimatedHeight), 0
    );
  };
  
  // 현재 스크롤 위치에서 보여야 할 아이템 찾기
  const findStartIndex = () => {
    let offset = 0;
    for (let i = 0; i < items.length; i++) {
      const height = heights.get(i) || estimatedHeight;
      if (offset + height > scrollTop) return Math.max(0, i - 2);
      offset += height;
    }
    return 0;
  };
  
  const startIndex = findStartIndex();
  const visibleItems = [];
  let currentOffset = getItemOffset(startIndex);
  
  for (let i = startIndex; i < items.length; i++) {
    if (currentOffset > scrollTop + containerHeight + 200) break;
    visibleItems.push({ item: items[i], index: i, offset: currentOffset });
    currentOffset += heights.get(i) || estimatedHeight;
  }
  
  return (
    
setScrollTop(e.target.scrollTop)} >
{visibleItems.map(({ item, index, offset }) => (
itemRefs.current.set(index, el)} style={{ position: 'absolute', top: offset, width: '100%' }} > {item.content}
))}
); }

5. 최적화 방법

스크롤 이벤트 쓰로틀링: 스크롤 이벤트는 매우 빈번하게 발생하므로 requestAnimationFrame이나 쓰로틀링을 적용하여 불필요한 리렌더링을 방지합니다. 메모이제이션: React.memo와 useMemo를 활용하여 변경되지 않은 아이템의 재렌더링을 방지합니다. Intersection Observer 활용: 뷰포트 진입/이탈 감지를 더 효율적으로 처리할 수 있습니다. 가변 높이 캐싱: 한 번 측정한 아이템 높이는 캐시하여 재계산을 방지합니다. 오버스캔 조정: 네트워크 환경과 데이터 복잡도에 따라 버퍼 크기를 동적으로 조정합니다.

// 스크롤 쓰로틀링 최적화
const useThrottledScroll = (callback, delay = 16) => {
  const timeoutRef = useRef(null);
  const lastRan = useRef(Date.now());
  
  return useCallback((e) => {
    if (Date.now() - lastRan.current >= delay) {
      callback(e);
      lastRan.current = Date.now();
    } else {
      clearTimeout(timeoutRef.current);
      timeoutRef.current = setTimeout(() => {
        callback(e);
        lastRan.current = Date.now();
      }, delay - (Date.now() - lastRan.current));
    }
  }, [callback, delay]);
};

6. 실전 활용 예제

React에서 가상 스크롤링 구현하기는 실무에서 다양하게 활용됩니다. 대용량 사용자 목록, 채팅 메시지 히스토리, 상품 카탈로그, 로그 뷰어 등에서 필수적입니다. react-window나 react-virtualized 같은 라이브러리를 사용할 수도 있지만, 직접 구현하면 프로젝트 특성에 맞게 커스터마이징할 수 있습니다.

// 실전 사용 예제
function App() {
  const items = Array.from({ length: 10000 }, (_, i) => ({
    id: i,
    content: `아이템 ${i + 1}`
  }));
  
  return (
    

가상 스크롤링 데모

); }

가상 스크롤링은 현대 웹 애플리케이션에서 대용량 데이터를 다룰 때 필수적인 최적화 기법입니다. 올바르게 구현하면 수만 개의 아이템도 부드럽게 렌더링할 수 있으며, 사용자 경험을 크게 향상시킬 수 있습니다.

📚 함께 읽으면 좋은 글

1

React에서 가상 스크롤링 구현하기 – 개념부터 구현까지 완벽 마스터

📂 알고리즘 해결
📅 2025. 11. 9.
🎯 React에서 가상 스크롤링 구현하기

2

React에서 가상 스크롤링 구현하기 – 개념부터 구현까지 완벽 마스터

📂 알고리즘 해결
📅 2025. 11. 8.
🎯 React에서 가상 스크롤링 구현하기

3

React에서 가상 스크롤링 구현하기 – 개념부터 구현까지 완벽 마스터

📂 알고리즘 해결
📅 2025. 11. 6.
🎯 React에서 가상 스크롤링 구현하기

4

배열 정렬 알고리즘 성능 비교 – 개념부터 구현까지 완벽 마스터

📂 알고리즘 해결
📅 2025. 11. 18.
🎯 배열 정렬 알고리즘 성능 비교

5

배열 정렬 알고리즘 성능 비교 – 개념부터 구현까지 완벽 마스터

📂 알고리즘 해결
📅 2025. 11. 18.
🎯 배열 정렬 알고리즘 성능 비교

💡 위 글들을 통해 더 깊이 있는 정보를 얻어보세요!

📢 이 글이 도움되셨나요? 공유해주세요!

여러분의 공유 한 번이 더 많은 사람들에게 도움이 됩니다 ✨

🔥 공유할 때마다 블로그 성장에 큰 힘이 됩니다! 감사합니다 🙏

💬 여러분의 소중한 의견을 들려주세요!

React에서 가상 스크롤링 구현하기 관련해서 궁금한 점이 더 있으시다면 언제든 물어보세요!

💡
유용한 정보 공유

궁금한 점 질문

🤝
경험담 나누기

👍
의견 표현하기

⭐ 모든 댓글은 24시간 내에 답변드리며, 여러분의 의견이 다른 독자들에게 큰 도움이 됩니다!
🎯 건설적인 의견과 경험 공유를 환영합니다 ✨

🔔 블로그 구독하고 최신 글을 받아보세요!

📚
다양한 주제
17개 카테고리

정기 업데이트
하루 3회 발행

🎯
실용적 정보
바로 적용 가능

💡
최신 트렌드
2025년 기준

🌟 알고리즘 해결부터 다양한 실생활 정보까지!
매일 새로운 유용한 콘텐츠를 만나보세요 ✨

📧 RSS 구독 | 🔖 북마크 추가 | 📱 모바일 앱 알림 설정
지금 구독하고 놓치는 정보 없이 업데이트 받아보세요!

답글 남기기