본문으로 건너뛰기

Infinite Scroll

Intersection Observer API를 활용한 고성능 무한 스크롤 Hook for React.

설치

npm install @windowing-kit/infinite-scroll
# 또는
pnpm add @windowing-kit/infinite-scroll
# 또는
yarn add @windowing-kit/infinite-scroll

빠른 시작

import { useInfiniteScroll } from "@windowing-kit/infinite-scroll";
import { useInfiniteState } from "./useInfiniteState";

function MyInfiniteList() {
const { items, loading, hasNextPage, fetchData } = useInfiniteState();

const { ref, isFetching } = useInfiniteScroll({
loading,
hasNextPage,
onLoadMore: fetchData,
rootMargin: "200px",
initialLoad: true,
});

return (
<div>
{items.map((item) => (
<div key={item.id}>{item.name}</div>
))}
<div ref={ref}>
{isFetching && <div>Loading...</div>}
{!hasNextPage && <div>No more items</div>}
</div>
</div>
);
}

API

useInfiniteScroll(options)

무한 스크롤 Hook입니다.

옵션

속성타입필수기본값설명
loadingboolean-현재 데이터를 로딩 중인지 여부
hasNextPageboolean-로드할 데이터가 더 있는지 여부
onLoadMore() => void | Promise<void>-더 많은 데이터를 로드하는 콜백 함수
rootMarginstring아니오"0px"Intersection Observer의 rootMargin 옵션
disabledboolean아니오false무한 스크롤을 비활성화할지 여부
delayInMsnumber아니오100onLoadMore를 트리거하기 전 지연 시간 (밀리초)
initialLoadboolean아니오false최초 마운트 시 자동으로 데이터를 로드할지 여부

반환값

속성타입설명
refVisibilityRefCallback트리거 요소(보통 마지막 아이템이나 센티널)에 연결할 ref callback
isFetchingboolean현재 데이터를 가져오는 중인지 여부 (loading 값과 동일)

예제

기본 사용법

function InfiniteList() {
const { items, hasNextPage, loading, fetchData } = useInfiniteState();

const { ref, isFetching } = useInfiniteScroll({
loading,
hasNextPage,
onLoadMore: fetchData,
});

return (
<div>
{items.map((item) => (
<Item key={item.id} item={item} />
))}
<div ref={ref}>{isFetching && <Spinner />}</div>
</div>
);
}

커스텀 Root Margin

const { ref, isFetching } = useInfiniteScroll({
loading,
hasNextPage,
onLoadMore: loadMore,
rootMargin: "300px", // 하단에 도달하기 300px 전에 로딩 시작
});

조건부 비활성화

const { ref, isFetching } = useInfiniteScroll({
loading,
hasNextPage,
onLoadMore: loadMore,
disabled: !user.isAuthenticated, // 사용자가 인증되지 않았으면 비활성화
});

초기 로드

const { ref, isFetching } = useInfiniteScroll({
loading,
hasNextPage,
onLoadMore: loadMore,
initialLoad: true, // 컴포넌트 마운트 시 자동으로 데이터 로드
});