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

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

1. 알고리즘 소개 및 개념

React에서 가상 스크롤링 구현하기는 대용량 리스트를 효율적으로 렌더링하기 위한 핵심 최적화 기법입니다. 수천, 수만 개의 데이터를 화면에 표시할 때 모든 항목을 DOM에 렌더링하면 심각한 성능 저하가 발생합니다. 가상 스크롤링(Virtual Scrolling)은 현재 뷰포트에 보이는 항목만 실제로 렌더링하고, 나머지는 메모리에만 유지하는 방식입니다. 이를 통해 10,000개 항목 중 실제로는 20~30개만 DOM에 존재하게 되어 초기 렌더링 속도가 획기적으로 개선되고 메모리 사용량도 크게 절감됩니다. React의 선언적 특성과 결합하면 사용자 경험을 해치지 않으면서도 고성능 리스트를 구현할 수 있습니다.

2. 동작 원리 상세 설명

가상 스크롤링의 핵심 원리는 ‘윈도잉(Windowing)’ 개념입니다. 전체 리스트의 높이는 CSS로 시뮬레이션하되, 실제 렌더링은 보이는 영역만 수행합니다. 구체적인 동작 과정은 다음과 같습니다.

첫째, 컨테이너의 높이와 각 항목의 높이를 기반으로 전체 스크롤 가능 영역을 계산합니다. 예를 들어 10,000개 항목이 각각 50px 높이라면 총 500,000px의 스크롤 영역이 필요합니다.

둘째, 스크롤 이벤트를 감지하여 현재 스크롤 위치(scrollTop)를 추적합니다. 이 값으로 현재 뷰포트에서 보여야 할 항목의 시작 인덱스와 종료 인덱스를 계산합니다.

셋째, 계산된 범위의 항목만 실제 DOM으로 렌더링하고, 상단에는 offsetY만큼의 여백을 추가하여 스크롤 위치를 정확하게 맞춥니다. 사용자가 스크롤할 때마다 이 계산이 반복되어 끊김 없는 스크롤 경험을 제공합니다.

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

시간 복잡도:

  • 초기 렌더링: O(V) – V는 뷰포트에 보이는 항목 수 (일반적으로 20~50개의 상수)
  • 스크롤 이벤트 처리: O(1) – 인덱스 계산만 수행
  • 리렌더링: O(V) – 새로 보이는 항목만 렌더링
  • 전체 리스트 순회 없이 항상 일정한 개수만 처리하므로 데이터 크기 N과 무관

공간 복잡도:

  • DOM 노드: O(V) – 뷰포트 항목만 유지
  • 데이터 저장: O(N) – 전체 데이터는 메모리에 유지
  • 일반 렌더링 O(N)과 비교하면 DOM 메모리를 99% 이상 절감 가능

예를 들어 10,000개 항목을 렌더링할 때, 일반 방식은 10,000개 DOM 노드를 생성하지만 가상 스크롤링은 30개만 생성하여 약 330배의 효율성을 보입니다.

4. 단계별 구현 과정

4.1 기본 구조 설정

먼저 가상 스크롤 컴포넌트의 기본 구조를 만들어봅시다. React에서 가상 스크롤링 구현하기의 첫 단계는 필요한 상태 값들을 정의하는 것입니다.

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

const VirtualScroll = ({ items, itemHeight, containerHeight }) => {
  const [scrollTop, setScrollTop] = useState(0);
  const containerRef = useRef(null);
  
  // 뷰포트에 보일 항목 수 계산
  const visibleCount = Math.ceil(containerHeight / itemHeight);
  
  // 버퍼를 포함한 시작/종료 인덱스 계산
  const startIndex = Math.max(0, Math.floor(scrollTop / itemHeight) - 2);
  const endIndex = Math.min(
    items.length - 1,
    startIndex + visibleCount + 4
  );
  
  // 실제 렌더링할 항목들
  const visibleItems = items.slice(startIndex, endIndex + 1);
  
  // 상단 오프셋 계산
  const offsetY = startIndex * itemHeight;
  
  return (
    
setScrollTop(e.target.scrollTop)} >
{visibleItems.map((item, index) => (
{item}
))}
); };

4.2 성능 최적화 – 스크롤 이벤트 쓰로틀링

스크롤 이벤트는 매우 빈번하게 발생하므로 쓰로틀링을 적용해야 합니다.

const useThrottle = (callback, delay) => {
  const lastRun = useRef(Date.now());
  
  return (...args) => {
    const now = Date.now();
    if (now - lastRun.current >= delay) {
      callback(...args);
      lastRun.current = now;
    }
  };
};

// 사용 예시
const handleScroll = useThrottle((e) => {
  setScrollTop(e.target.scrollTop);
}, 16); // 약 60fps

4.3 동적 높이 지원

항목마다 높이가 다른 경우를 처리하는 고급 구현입니다.

const VirtualScrollDynamic = ({ items, estimatedItemHeight, containerHeight }) => {
  const [itemHeights, setItemHeights] = useState({});
  const [scrollTop, setScrollTop] = useState(0);
  
  // 각 항목의 누적 높이 계산
  const getItemOffset = (index) => {
    let offset = 0;
    for (let i = 0; i < index; i++) {
      offset += itemHeights[i] || estimatedItemHeight;
    }
    return offset;
  };
  
  // 높이 측정 콜백
  const measureHeight = (index, element) => {
    if (element) {
      const height = element.getBoundingClientRect().height;
      setItemHeights(prev => ({ ...prev, [index]: height }));
    }
  };
  
  return (
    
setScrollTop(e.target.scrollTop)} > {visibleItems.map((item, index) => (
measureHeight(index, el)} style={{ position: 'absolute', top: getItemOffset(index) }} > {item}
))}
); };

4.4 실용적인 완성 예제

const App = () => {
  // 10,000개 테스트 데이터 생성
  const items = Array.from({ length: 10000 }, (_, i) => 
    `항목 ${i + 1} - ${Math.random().toString(36).substring(7)}`
  );
  
  return (
    

가상 스크롤링 데모

); }; export default App;

5. 최적화 방법

5.1 메모이제이션 활용

React에서 가상 스크롤링 구현하기를 더욱 최적화하려면 불필요한 재계산을 방지해야 합니다.

import { useMemo } from 'react';

const visibleItems = useMemo(() => {
  const start = Math.floor(scrollTop / itemHeight);
  const end = start + visibleCount;
  return items.slice(start, end);
}, [scrollTop, items, itemHeight, visibleCount]);

5.2 IntersectionObserver 활용

더 정밀한 가시성 감지를 위해 IntersectionObserver를 사용할 수 있습니다.

useEffect(() => {
  const observer = new IntersectionObserver(
    (entries) => {
      entries.forEach(entry => {
        if (entry.isIntersecting) {
          // 추가 데이터 로딩 등
        }
      });
    },
    { rootMargin: '100px' }
  );
  
  return () => observer.disconnect();
}, []);

5.3 리스트 라이브러리 활용

프로덕션 환경에서는 검증된 라이브러리 사용을 권장합니다. react-window와 react-virtualized가 대표적입니다.

import { FixedSizeList } from 'react-window';

const OptimizedList = ({ items }) => (
  
    {({ index, style }) => (
      
{items[index]}
)}
);

6. 실전 활용 예제

6.1 무한 스크롤 구현

const InfiniteVirtualScroll = ({ fetchData }) => {
  const [items, setItems] = useState([]);
  const [isLoading, setIsLoading] = useState(false);
  
  const handleScroll = (e) => {
    const { scrollTop, scrollHeight, clientHeight } = e.target;
    
    if (scrollHeight - scrollTop <= clientHeight * 1.5 && !isLoading) {
      setIsLoading(true);
      fetchData().then(newItems => {
        setItems(prev => [...prev, ...newItems]);
        setIsLoading(false);
      });
    }
  };
  
  return (
    
  );
};

6.2 검색 필터링과 결합

const SearchableVirtualList = ({ allItems }) => {
  const [searchTerm, setSearchTerm] = useState('');
  
  const filteredItems = useMemo(() => 
    allItems.filter(item => 
      item.toLowerCase().includes(searchTerm.toLowerCase())
    ),
    [allItems, searchTerm]
  );
  
  return (
    
setSearchTerm(e.target.value)} />
); };

결론

React에서 가상 스크롤링 구현하기는 대용량 데이터를 다루는 현대 웹 애플리케이션에서 필수적인 기술입니다. 기본 원리를 이해하고 단계별로 구현하면 일반 렌더링 대비 수백 배의 성능 향상을 얻을 수 있습니다. 초기에는 직접 구현하여 개념을 익히고, 실무에서는 react-window 같은 검증된 라이브러리를 활용하는 것이 효율적입니다. 이 가이드의 코드를 실제 프로젝트에 적용하여 사용자 경험을 획기적으로 개선해보세요.

📚 함께 읽으면 좋은 글

1

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

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

2

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

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

3

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

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

4

JavaScript로 이진 탐색 구현하기 – 개념부터 구현까지 완벽 마스터

📂 알고리즘 해결
📅 2025. 11. 7.
🎯 JavaScript로 이진 탐색 구현하기

5

재귀 함수 마스터하기 – 개념부터 구현까지 완벽 가이드

📂 알고리즘 해결
📅 2025. 11. 7.
🎯 재귀 함수 마스터하기

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

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

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

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

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

이 글을 읽고 새롭게 알게 된 정보가 있다면 공유해주세요!

💡
유용한 정보 공유

궁금한 점 질문

🤝
경험담 나누기

👍
의견 표현하기

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

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

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

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

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

💡
최신 트렌드
2025년 기준

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

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

답글 남기기