TanStack Virtual을 사용한 가상화

발행: (2026년 2월 18일 오전 05:39 GMT+9)
9 분 소요
원문: Dev.to

Source: Dev.to

성능 최적화는 React 커뮤니티에서 흔히 다루는 주제입니다. 사용자는 특히 수천 개에 달하는 대규모 데이터셋을 다룰 때 부드러운 스크롤링과 빠른 상호작용을 기대합니다.

Virtualisation은 수천 개의 DOM 요소를 한 번에 로드하는 대신, 보이는 요소(및 작은 버퍼)만 표시함으로써 큰 리스트를 개선합니다. 사용자가 스크롤할 때 요소가 동적으로 추가 및 제거되며, 리스트는 성능 저하 없이 전체 데이터셋이 모두 렌더링된 것처럼 보이게 유지됩니다.

가상화가 필수적인 이유

대규모 데이터셋을 처리할 때:

  • Memory consumption – Rendering numerous DOM elements utilises a considerable amount of memory.
    메모리 사용량 – 많은 DOM 요소를 렌더링하면 상당한 메모리를 사용합니다.
  • Initial rendering speed – The initial display slows down as React builds and reconciles a large tree.
    초기 렌더링 속도 – React가 큰 트리를 구축하고 조정하면서 초기 화면 표시가 느려집니다.
  • Scrolling responsiveness – Working with large datasets increases the workload and DOM size, leading to sluggish scrolling.
    스크롤 반응성 – 대규모 데이터셋을 다루면 작업 부하와 DOM 크기가 증가해 스크롤이 느려집니다.
  • User experience – The application may feel malfunctioning because of the slow response when scrolling and tapping.
    사용자 경험 – 스크롤 및 탭 시 응답이 느려 애플리케이션이 제대로 작동하지 않는 듯한 느낌을 줄 수 있습니다.

Virtualisation significantly reduces the DOM node count, often resulting in smoother scrolling and faster interactions. Various methods exist for implementing virtualisation in React. In this piece, we’ll concentrate on TanStack Virtual.
가상화는 DOM 노드 수를 크게 줄여 스크롤이 부드러워지고 상호작용이 빨라지는 경우가 많습니다. React에서 가상화를 구현하는 다양한 방법이 있으며, 이번 글에서는 TanStack Virtual에 집중하겠습니다.

TanStack Virtual 소개

TanStack Virtual은 헤드리스 가상화 라이브러리입니다. 사전 구축된 UI 컴포넌트를 포함하지 않습니다. 대신, 가상화 엔진(범위, 오프셋, 전체 크기 및 측정 유틸리티)을 제공하여 마크업, 스타일링, 레이아웃 및 인터랙션을 완전히 제어할 수 있게 합니다. 이는 리스트 항목이 단순한 행이 아니라 배지, 메뉴, 이미지, 버튼 및 복잡한 디자인과 같은 정교한 UI 요소일 때 특히 유용합니다.

설치

npm install @tanstack/react-virtual
# or
yarn add @tanstack/react-virtual
# or
pnpm add @tanstack/react-virtual

TanStack Virtual 기본 이해

TanStack Virtual은 앱에 넣고 잊어버리는 UI 컴포넌트 라이브러리가 아닙니다. 가상화의 어려운 부분을 처리하는 가벼운 유틸리티로, 다음을 결정합니다:

  • 어떤 항목을 보여줄지,
  • 그 항목들을 스크롤 공간에서 어디에 배치할지,
  • 전체 목록이 얼마나 크게 보일지 (스크롤바가 자연스럽게 동작하도록).

UI는 여전히 직접 구축합니다: 마크업, 스타일링, 레이아웃, 인터랙션 등.

이제 단계별로 분석해 보겠습니다.

멘탈 모델 (“환상”)

가상 리스트는 일반적으로 세 가지 요소로 구성됩니다:

  1. Scroll container – 고정된 높이와 overflow: auto를 가진 div.
  2. Spacer – 전체 리스트 높이(getTotalSize())를 가진 내부 요소.
  3. Virtual items – 보이는 아이템만, transform: translateY(...)를 사용해 위치시킴.

예시

import { useVirtualizer } from "@tanstack/react-virtual";

export function BasicVirtualList() {
  const parentRef = React.useRef(null);

  const items = React.useMemo(
    () => Array.from({ length: 100_000 }, (_, i) => `Item ${i + 1}`),
    []
  );

  const virtualizer = useVirtualizer({
    count: items.length,
    getScrollElement: () => parentRef.current,
    estimateSize: () => 44, // fixed row height
    overscan: 8,
  });

  return (
    <div ref={parentRef} style={{ height: "400px", overflow: "auto" }}>
      <div style={{ height: virtualizer.getTotalSize() }}>
        {virtualizer.getVirtualItems().map((vItem) => (
          <div
            key={vItem.key}
            style={{
              position: "absolute",
              top: 0,
              left: 0,
              width: "100%",
              height: `${vItem.size}px`,
              transform: `translateY(${vItem.start}px)`,
            }}
          >
            {items[vItem.index]}
          </div>
        ))}
      </div>
    </div>
  );
}

모든 구현에 사용할 핵심 개념

  • estimateSize – 추정된 아이템 높이(또는 가로 리스트의 경우 너비)를 반환하는 함수.
  • getItemKey – 정렬, 필터링, 혹은 새로운 데이터 등으로 리스트가 변경될 수 있을 때 일관된 키를 사용하여 가상화가 안정적으로 유지되도록 합니다.
  • overscan – 뷰포트 위와 아래에 추가로 렌더링할 아이템 수를 제어합니다. overscan 값을 높이면 빠른 스크롤 시 빈 공간이 줄어들지만, 스크롤당 작업량이 증가합니다.

구성 외에도 실제적인 요소들이 애플리케이션에서 가상화의 효율성에 영향을 줄 수 있습니다.

Tips for Virtualisation

  • Fixed vs. variable item height – Fixed layouts are simpler; variable heights require measuring and managing sizes carefully.
  • Row state – Virtualised rows may mount and unmount as you scroll. Ensure critical data or state isn’t stored only inside the row components themselves.
  • Focus & accessibility – When a row is unmounted, input and keyboard navigation may break if focus disappears.
  • Images and dynamic content – Media that loads slowly can change heights, causing scroll jumps if not handled properly.
  • Performance proof – Compare results before and after using the React Profiler and Chrome Performance tools.

일반적인 함정 (그리고 …)

이 섹션의 내용은 나중에 추가될 수 있습니다.

이를 방지하는 방법

베스트 프랙티스를 따르더라도 가상화된 리스트는 미묘한 버그와 성능 문제를 일으킬 수 있습니다. 아래는 흔히 발생하는 문제와 해결책입니다.

  • 빠른 스크롤 시 빈 공간 발생
    overscan 값을 약간 늘려서 보이는 뷰포트 밖까지 더 많은 아이템을 렌더링합니다.

  • 가변 콘텐츠로 인한 스크롤 점프
    이미지에 고정 높이 또는 aspect‑ratio를 지정해 공간을 예약하거나, 정확한 측정을 활성화하여 동적 높이 변화로 인한 스크롤 위치 이동을 방지합니다.

  • 행 상태 손실
    상태를 끌어올려 id 로 저장합니다. 행 컴포넌트 내부에만 중요한 상태를 두지 마세요. 스크롤 중에 해당 컴포넌트가 마운트·언마운트될 수 있습니다.

  • 잘못된 키 사용
    리스트 순서가 바뀔 수 있는 경우 getItemKey 로 안정적인 키를 사용합니다. 배열 인덱스에 의존하지 마세요.

마무리

가상화는 React에서 방대한 리스트에 적용할 수 있는 가장 효과적인 성능 향상 중 하나입니다. TanStack React Virtual를 사용하면 다재다능하고 헤드리스 엔진을 얻을 수 있으며, 실제 애플리케이션에 원활하게 통합됩니다—특히 UI 레이아웃을 완전히 제어해야 할 때 유용합니다.

0 조회
Back to Blog

관련 글

더 보기 »

Inertia.js가 조용히 앱을 깨뜨립니다

TL;DR 프로덕션 Laravel 12 + React 19 + Inertia v2 앱에서 몇 주 동안 작업하면서, 진단 비용이 많이 드는 실패 모드에 반복적으로 부딪혔습니다: overlapping visit can...