무한스크롤 이란?
무한 스크롤은 웹사이트나 애플리케이션에서 사용되는 사용자 경험 기법 중 하나입니다. 일반적으로 긴 목록이나 콘텐츠가 있는 페이지에서 스크롤을 내리면, 새로운 콘텐츠가 자동으로 로드되어 사용자가 페이지를 더 이상 끝까지 스크롤하지 않고도 계속해서 내용을 볼 수 있게 됩니다.
무한 스크롤은 사용자가 페이지를 일일히 다음 페이지로 이동하지 않고도 계속해서 콘텐츠를 탐색할 수 있도록 합니다. 이는 특히 소셜 미디어 피드, 뉴스 웹사이트, 온라인 상점 등 콘텐츠가 계속해서 업데이트되는 경우에 유용합니다. 사용자는 스크롤을 하면서 새로운 콘텐츠가 자동으로 로드되기 때문에, 일정한 페이지 간격을 넘어갈 필요가 없고 보다 빠르고 원활한 사용자 경험을 제공합니다.
무한스크롤 왜 사용하였나?
저는 사이드 프로젝트로 NFT 거래소를 만들고 있는데 NFT 컬렉션 하나당 많게는 10000개 이상 최소 1000개 이상의 아이템들이 있기때문에 무한스크롤이 적합하다고 판단되어 무한스크롤을 구현해보았습니다.
준비물
- React-query 설치
- npm i react-query
- react-intersection-observer 설치
- npm i react-intersection-observer
Rreact-query 의 useInfinityQuery hook 과 react-intersection-observer 의 hook 을 사용하여 무한스크롤을 구현해보겠습니다
useInfinityQuery 커스텀훅으로 만들기
import { useInfiniteQuery } from "@tanstack/react-query";
import { getCollectionListOpenSea } from "@/api/CollectionAPI";
import { CollectionList } from "@/types/types";
import { useEffect } from "react";
import { useInView } from "react-intersection-observer";
import CollectionListLoading from "@/components/ui/Skeleton/CollectionListLoading";
export const useGetCollectionList = (collectionName: string) => {
const {
data,
isLoading,
fetchNextPage,
hasNextPage,
isFetchingNextPage,
isSuccess,
} = useInfiniteQuery(
["OpenSeaCollectionList", collectionName],
async ({ pageParam }): Promise<CollectionList> =>
await getCollectionListOpenSea(collectionName, pageParam),
{
getNextPageParam: (lastPage) => {
return lastPage.next ?? undefined;
},
select: (data) => ({
pageParams: data.pageParams,
pages: data?.pages.flatMap((page) => page.nfts),
}),
}
);
const Observer = () => {
const [ref, inView] = useInView({ threshold: 0 });
useEffect(() => {
if (!data || !hasNextPage) return;
if (hasNextPage && inView) fetchNextPage();
}, [inView]);
return isFetchingNextPage ? (
<CollectionListLoading skeletonCount={12} />
) : (
<div ref={ref} />
);
};
return { data, isLoading, fetchNextPage, Observer, isSuccess };
};
첫번째 쿼리키 배열에 첫번째 인자로 쿼리키 를 구분해줄 키값을 넣어주었으며 두번째로는 collectionName 이 바뀔때마다 다시 fetching하도록 도와주는 값입니다. 두번째 인자는 쉽게 설명하면 useEffect의 의존성배열로 생각해주시면 될 것 같습니다.
pageParam 은 다음페이지를 불러올 값이며 getNextPageParam 에서 return 되는값은 pageParam 이 됩니다.
const optionsOpensea = {
method: "GET",
headers: { "X-API-KEY": process.env.NEXT_PUBLIC_OPENSEA_API_KEY as string },
};
export const getCollectionListOpenSea = async (slug: string, next?: string) => {
try {
let url = `https://api.opensea.io/v2/collection/${slug}/nfts?limit=12`;
if (next) {
url += `&next=${next}`;
}
const res = await fetch(url, optionsOpensea);
return await res.json();
} catch (error) {
console.log(error);
throw new Error("Failed to fetch OpenSea-API CollectionList data");
}
};
데이터를 fetch 하는 함수내부입니다. 현재 몇페이지를 알려주는 pageParam값은 next라는 매개변수로 받아주고 있습니다.
첫 데이터 요청엔 pageParam이 필요없기때문에 next없이 요청을보낸후 두번째 요청일때 현재 몇페이지를 원하는지를 붙여서 서버에 요청을 보냅니다.
const {
data,
isLoading,
fetchNextPage,
hasNextPage,
isFetchingNextPage,
isSuccess,
} = useInfiniteQuery(
["OpenSeaCollectionList", collectionName],
async ({ pageParam=1 }): Promise<CollectionList> =>
await getCollectionListOpenSea(collectionName, pageParam),
{
getNextPageParam: (lastPage) => {
return lastPage.next + 1 ?? undefined;
},
이해를 돕기위해 예시 코드를 작성해봤습니다. pageParam 을 기본값 1로 하여 처음 요청을 보냅니다.
보통 무한스크롤 데이터를 받는 API 를 요청할때 어디 페이지를 불러올것인지에 대한 매개변수를 같이 보내주어야 할것입니다. 그래야 백엔드에서 어디페이지를 잘라서 줄지 알수가 있습니다.
getNextPageParam 에서는 데이터요청을 보낸후 요청 응답값인 next에 1을더해 다시 pageParam 으로 반환합니다.
이렇게된다면 두번째 요청에선 pageParam은 2가 되어서 다시 2번째 페이지 데이터들을 보내줄것입니다.
만약 응답값에 현재페이지와 관련된 데이터가 없다면 백엔드 분께 요청해서 현재 몇페이지인지 넣어달라고 하시면 됩니다.
Observer 를 사용하여 무한스크롤을 트리거 하는법 은 글 이 길어져 다음글 에서 설명하겠습니다.
'FrontEnd' 카테고리의 다른 글
FrontEnd - 재사용성 높인 버튼 공통컴포넌트 만들어보기 with.tailwindcss (0) | 2023.07.09 |
---|---|
FrontEnd - React-query 를 이용한 무한스크롤 구현하기 - (2) (0) | 2023.07.06 |
Frontend - 프론트엔드 웹 성능 최적화 도전기 with Next.js (0) | 2023.07.03 |
Frontent - SSR(ServerSideRendering) vs CSR(ClientSideRendering) (0) | 2023.06.29 |
AWS Lambda 란 무엇인가? (0) | 2023.06.29 |