본문으로 건너뛰기

Virtual List

고성능 가상화 리스트 Hook for React. 보이는 아이템만 렌더링하여 대용량 리스트를 효율적으로 처리합니다.

설치

npm install @windowing-kit/virtual-list
# 또는
pnpm add @windowing-kit/virtual-list
# 또는
yarn add @windowing-kit/virtual-list

빠른 시작

import { useVirtualList } from "@windowing-kit/virtual-list";

function MyList() {
const items = Array.from({ length: 10000 }, (_, i) => ({
id: i,
name: `Item ${i}`,
}));

const { containerRef, listHeight, virtualItems } = useVirtualList({
itemHeight: 50,
items,
overscan: 3,
});

return (
<div
ref={containerRef}
style={{
height: "400px",
overflow: "auto",
}}
>
<div style={{ height: listHeight, position: "relative" }}>
{virtualItems.map((virtualItem) => (
<div
key={virtualItem.index}
style={{
position: "absolute",
top: virtualItem.offsetY,
height: 50,
width: "100%",
}}
>
{virtualItem.data.name}
</div>
))}
</div>
</div>
);
}

API

useVirtualList<T>(options)

가상화 리스트 Hook입니다.

옵션

속성타입필수기본값설명
itemHeightnumber-각 아이템의 높이 (픽셀 단위)
itemsT[]-렌더링할 전체 아이템 배열
overscannumber아니오3뷰포트 밖에 미리 렌더링할 아이템 수

반환값

속성타입설명
containerRef(element: HTMLElement | null) => void스크롤 컨테이너에 연결할 ref callback
listHeightnumber전체 리스트의 총 높이 (픽셀 단위)
virtualItemsVirtualItem<T>[]현재 뷰포트에 보이는 가상 아이템 배열

VirtualItem<T>

각 가상 아이템은 다음 속성을 가집니다:

속성타입설명
indexnumber원본 배열에서의 인덱스
offsetYnumber리스트 내에서의 Y 오프셋 (픽셀 단위)
dataT원본 아이템 데이터

예제

기본 사용법

import { useVirtualList } from "@windowing-kit/virtual-list";

function TodoList({ todos }) {
const { containerRef, listHeight, virtualItems } = useVirtualList({
itemHeight: 60,
items: todos,
overscan: 5,
});

return (
<div ref={containerRef} style={{ height: "500px", overflow: "auto" }}>
<div style={{ height: listHeight, position: "relative" }}>
{virtualItems.map((virtualItem) => (
<div
key={virtualItem.index}
style={{
position: "absolute",
top: virtualItem.offsetY,
height: 60,
width: "100%",
padding: "10px",
borderBottom: "1px solid #eee",
}}
>
{virtualItem.data.title}
</div>
))}
</div>
</div>
);
}

커스텀 스타일링

function StyledList({ items }) {
const { containerRef, listHeight, virtualItems } = useVirtualList({
itemHeight: 80,
items,
});

return (
<div
ref={containerRef}
className="scroll-container"
style={{ height: "600px", overflow: "auto" }}
>
<div style={{ height: listHeight, position: "relative" }}>
{virtualItems.map((virtualItem) => (
<div
key={virtualItem.index}
className="list-item"
style={{
position: "absolute",
top: virtualItem.offsetY,
height: 80,
width: "100%",
}}
>
<h3>{virtualItem.data.title}</h3>
<p>{virtualItem.data.description}</p>
</div>
))}
</div>
</div>
);
}