1. Next.js 프로젝트 생성
npx create-next-app@latest infinite-scroll --typescript
cd infinite-scroll
npm install
2. 무한 스크롤 컴포넌트 작성
components/InfiniteScroll.tsx 파일 생성, 외부 API를 호출하도록 수정
// components/InfiniteScroll.tsx
import { useState, useEffect, useRef, useCallback } from 'react';
// 외부 API에서 데이터를 가져오는 비동기 함수
const fetchMoreData = async (page: number, limit: number) => {
// https://jsonplaceholder.typicode.com라는 test용 restAPI를 통해 dummy json data를 보여줌
const res = await fetch(`https://jsonplaceholder.typicode.com/posts?_page=${page}&_limit=${limit}`);
const newData = await res.json();
return newData;
};
const InfiniteScroll = () => {
const [data, setData] = useState<any[]>([]); // 데이터를 저장하는 상태
const [page, setPage] = useState(1); // 현재 페이지 번호를 저장하는 상태
const [loading, setLoading] = useState(false); // 로딩 상태를 저장하는 상태
const observerRef = useRef<IntersectionObserver | null>(null); // Intersection Observer 참조를 저장하는 ref
const loadMoreRef = useRef<HTMLDivElement | null>(null); // 로드 모어 div 참조를 저장하는 ref
// 초기 데이터를 로드하는 useEffect
useEffect(() => {
const loadInitialData = async () => {
setLoading(true);
const initialData = await fetchMoreData(1, 10);
setData(initialData);
setLoading(false);
};
loadInitialData();
}, []);
// 더 많은 데이터를 로드하는 함수
const loadMore = async () => {
setLoading(true);
const newPage = page + 1;
const newData = await fetchMoreData(newPage, 10);
setData((prevData) => [...prevData, ...newData]);
setPage(newPage);
setLoading(false);
};
// Intersection Observer의 콜백 함수
const handleObserver = useCallback(
(entries: IntersectionObserverEntry[]) => {
const target = entries[0];
if (target.isIntersecting) {
loadMore();
}
},
[page]
);
// Intersection Observer를 설정하는 useEffect
useEffect(() => {
observerRef.current = new IntersectionObserver(handleObserver, {
rootMargin: '20px',
});
if (loadMoreRef.current) {
observerRef.current.observe(loadMoreRef.current);
}
return () => {
if (loadMoreRef.current) {
observerRef.current?.unobserve(loadMoreRef.current);
}
};
}, [handleObserver]);
return (
<div>
<ul>
{data.map((item) => (
<li key={item.id}>{item.title}</li>
))}
</ul>
<div ref={loadMoreRef} style={{ height: '20px', backgroundColor: 'transparent' }} />
{loading && <p>Loading...</p>}
</div>
);
};
export default InfiniteScroll;
코드 설명
- fetchMoreData: JSONPlaceholder API를 호출하여 데이터를 가져오는 비동기 함수입니다. _page와 _limit 쿼리 파라미터를 사용하여 페이지네이션을 처리합니다.
- InfiniteScroll 컴포넌트는 이전과 동일한 방식으로 동작하지만, 데이터를 외부 API에서 가져옵니다.
4. 페이지에서 컴포넌트 사용
pages/index.tsx 에서 InfiniteScroll 컴포넌트를 사용
// pages/index.tsx
import InfiniteScroll from '../components/InfiniteScroll';
const Home = () => {
return (
<div>
<h1>무한 스크롤 예제</h1>
<InfiniteScroll />
</div>
);
};
export default Home;
프로젝트 실행
프로젝트를 실행하여 결과 확인
npm run dev
Github URL
'Programming > Next' 카테고리의 다른 글
Next.js(typescript) + Socket.IO 실시간 채팅 구현(simple ver.) (0) | 2024.06.17 |
---|