반응형
백엔드는 프리즈마 ORM을 사용했고 커서기반으로 구현했습니다
Page
const ItemPage = () => {
const TAKE = 10;
const MEMBER_ID = 1; // 1 ~ 5
const FIRST_CURSOR = 1;
const { data, fetchNextPage, hasNextPage, isFetching } =
useInfiniteFindItemsQuery(
{
memberId: MEMBER_ID,
lastCursorId: FIRST_CURSOR,
},
{
getNextPageParam: (lastPage, allPages) => {
if (lastPage.findItems.length === 0) {
return undefined;
} else {
return {
memberId: MEMBER_ID,
lastCursorId:
lastPage.findItems[lastPage.findItems.length - 1]?.id + 1,
};
}
},
enabled: false,
initialPageParam: {
memberId: MEMBER_ID,
lastCursorId: FIRST_CURSOR,
},
},
);
useEffect(() => {
fetchNextPage();
}, []);
const observerRef = useIntersectionObserver({
isFetching,
hasNextPage,
fetchNextPage,
});
return (
<main className="mx-24 my-16">
<SearchBar />
{/*<Suspense fallback={ItemPage.Skeleton()}>*/}
<div className="grid grid-cols-5 gap-x-14">
{data?.pages.map((page, pageNum) =>
page.findItems.map((item, index) => (
<Item index={index + pageNum * TAKE} key={item.id} item={item} />
)),
)}
</div>
{/*</Suspense>*/}
<div ref={observerRef} className="h-1" />
</main>
);
};
export default ItemPage;
최하단 엘리먼트 요소 감지 훅 및 다음 페이지 데이터 Fetch
import React, { useCallback, useEffect, useRef, useState } from 'react';
import {
FetchNextPageOptions,
InfiniteData,
InfiniteQueryObserverResult,
} from '@tanstack/react-query';
import { IFindItemsQuery } from '@/gql/generated/graphql';
//hook props interface
interface IuseIntersectionObserverProps<TData = unknown> {
isFetching: boolean | undefined;
hasNextPage: boolean | undefined;
fetchNextPage: (
options?: FetchNextPageOptions,
) => Promise<
InfiniteQueryObserverResult<InfiniteData<TData, unknown>, unknown>
>;
}
export const useIntersectionObserver = <TData>({
isFetching,
hasNextPage,
fetchNextPage,
}: IuseIntersectionObserverProps<TData>) => {
const options = {
root: null, // 감지할 대상 지정 null일 경우 뷰포트가 대상
rootMargin: '0px', // root요소가 가장자리에 도달하는 즉시 교차 이벤트 감지
threshold: 1.0, // 얼마나 많이 root요소와 교차하는지 설정 → 1.0 = 100% 완전히 겹친다
};
const handleIntersection = useCallback(
(entries: IntersectionObserverEntry[]) => {
const target = entries[0];
if (target.isIntersecting && hasNextPage && !isFetching) {
fetchNextPage();
}
},
[hasNextPage, isFetching, fetchNextPage],
);
const observerRef = useRef(null);
useEffect(() => {
const observer = new IntersectionObserver(handleIntersection, options);
if (observerRef.current) {
observer.observe(observerRef.current);
}
return () => {
observer.disconnect();
};
}, [handleIntersection, options]);
return observerRef;
};
반응형
'[React] > [React Code]' 카테고리의 다른 글
[React Code] 다중 라디오버튼(radio) 생성 (상태 관리 [전역 Redux]) (1) | 2024.02.07 |
---|---|
[React Code] 다중 체크박스(checkbox) 구현 (상태 관리 [전역 Redux / 지역]) → 배열로 상태관리 (0) | 2024.02.07 |
[React Code] 다중 버튼중 단일 선택 기능 (4) | 2023.11.22 |