프로젝트를 진행하면서 페이지네이션을 구현해 봤는데, 이걸 무한 스크롤로 바꾼다면 어떻게 구현해야 하고 무엇이 달라질지 궁금점이 생겼다. 그래서 이번 기회에 2개의 차이점과 어떻게 구현하는지에 대해 정리해 보았다.
게시글이나 상품처럼 데이터가 많은 서비스를 만든다고 가정했을 때 서버에 모든 데이터를 한 번에 가져온다면 어떤 문제가 생길까?
- 로딩 속도가 느려진다.
- 브라우저 메모리 사용량이 증가한다.
- 렌더링 성능이 저하된다.
- 사용자가 원하는 데이터를 탐색하기 어려워진다.
그래서 실제 서비스에서는 데이터를 일정 단위로 나누어 가져오는 방식이 사용된다. 그 방식이 바로 Pagination(페이지네이션)과 Infinite Scroll(무한스크롤)이다!
Pagination 이란?
Pagination은 데이터를 페이지 단위로 나누어 보여주는 방식이다.

| 장점 | 단점 |
| 원하는 페이지로 바로 이동 가능 | 버튼 클릭이 필요 |
| 현재 위치 파악이 쉬움 | 흐름이 끊길 수 있음 |
| SEO에 유리 | 모바일 UX가 상대적으로 불편 |
| 데이터 관리가 단순함 |
Pagination의 핵심은 현재 페이지 상태를 관리하고, 페이지가 변경될 때 데이터를 다시 요청하는 것이다.
1) 현재 페이지 상태 관리
const [page, setPage] = useState(1);
const [posts, setPosts] = useState([]);
2) page가 변경될 때 데이터 요청
useEffect(() => {
fetchPosts(page);
}, [page]);
3) 데이터 요청 함수
const fetchPosts = async (page: number) => {
const response = await fetch(
`/api/posts?page=${page}&limit=10`
);
const data = await response.json();
setPosts(data);
};
4) 페이지 이동 버튼
<button onClick={() => setPage(page - 1)}>
이전
</button>
<button onClick={() => setPage(page + 1)}>
다음
</button>
Infinite Scroll 이란?
Infinite Scroll은 사용자가 스크롤을 내릴 때 다음 데이터를 자동으로 불러오는 방식이다.

| 장점 | 단점 |
| 몰입감이 좋음 | footer 접근이 어려움 |
| 모바일 환경에 적합 | 현재 위치 기억이 어려움 |
| 클릭 없이 탐색 가능 | 렌더링 성능 관리 필요 |
Pagination vs Infinite Scroll
- Pagination : 기존 데이터를 새로운 데이터로 교체한다.
- Infinite Scroll : 기존 데이터 뒤에 새로운 데이터를 추가한다.
Infinite Scroll은 어떻게 동작할까?
스크롤 하단 도달 → 다음 데이터 요청 → 기존 데이터 아래 추가 → 다시 스크롤 → 반복
이 과정을 거쳐서 동작한다. 그렇다면 React에서는 어떻게 스크롤 하단 도달을 알 수 있을지 찾아보았다.
우선 맨 아래에 감시용 div를 만든다.

사용자가 스크롤을 내려 감시용 div가 화면에 보이면 다음 데이터를 요청한다. 그다음, Intersection Observer을 사용한다. 이를 코드로 구현하면 아래의 코드이다.
import { useEffect, useRef, useState } from "react";
function InfiniteScroll() {
// 게시글 목록 상태
const [posts, setPosts] = useState([]);
// 현재 페이지 상태
const [page, setPage] = useState(1);
// 감시할 요소 ref
const targetRef = useRef(null);
// 게시글 요청 함수
const fetchPosts = async () => {
const response = await fetch(
`/api/posts?page=${page}&limit=10`
);
const data = await response.json();
// 기존 데이터 뒤에 새 데이터 추가
setPosts(prev => [...prev, ...data]);
};
// page가 변경될 때마다 데이터 요청
useEffect(() => {
fetchPosts();
}, [page]);
// Intersection Observer 설정
useEffect(() => {
const observer = new IntersectionObserver((entries) => {
// 감시 요소가 화면에 보이면
if (entries[0].isIntersecting) {
// 다음 페이지 요청
setPage(prev => prev + 1);
}
});
// 감시 시작
if (targetRef.current) {
observer.observe(targetRef.current);
}
// observer 정리
return () => observer.disconnect();
}, []);
return (
<>
{/* 게시글 목록 렌더링 */}
{posts.map(post => (
<div key={post.id}>
{post.title}
</div>
))}
{/* 화면 하단 감시 요소 */}
<div ref={targetRef} />
</>
);
}
Infinite Scroll은 단순 구현보다 실제 서비스에서 안정적으로 동작하는 과정이 더 중요하다. 먼저, Intersection Observer는 스크롤 상황에 따라 여러 번 실행될 수 있기 때문에 중복 요청을 방지해야 한다.
if (isFetching) return;
같은 조건을 통해 이미 데이터를 요청 중일 때는 추가 요청이 발생하지 않도록 처리한다.
또한, 마지막 페이지 이후에도 계속 요청하지 않도록 다음 데이터 존재 여부를 관리해야 한다.
hasNextPage
값을 활용해 더 이상 불러올 데이터가 없으면 요청을 중단할 수 있다.
추가로 Infinte Scroll은 데이터가 계속 누적되는 구조라서 게시글 수가 많아질수록 DOM 요소도 증가한다. 이 경우 렌더링 성능이 저하될 수 있어서 화면에 보이는 요소만 렌더링 하는 virtualization 기법을 사용하기도 한다. 대표적으로 react-window, react-virtualized 같은 라이브러리를 사용한다.
마무리
Pagination과 Infinite Scroll은 단순 UI 차이가 아니라 사용자 경험과 데이터 탐색 방식의 차이이다.
- Pagination은 탐색 효율에 강점이 있다.
- Infinite Scroll은 콘텐츠 몰입에 강점이 있다.
'💻 STUDY > Frontend' 카테고리의 다른 글
| React는 왜 Suspense를 만들었을까? (1) | 2026.05.21 |
|---|---|
| useState의 snapshot과 batching (0) | 2026.05.17 |
| Tailwind CSS가 가벼운 이유 (0) | 2026.05.05 |
| Three.js 정리하기 (0) | 2026.04.16 |
| React 렌더링 최적화에 대해서 (0) | 2026.04.15 |