페이지 처리 방법에 관한 고찰
✒️ 2025-05-28 10:00 내용 수정
- 프로젝트를 진행하면서 내가 작성한 페이지 처리 방법과 팀원이 작성한 페이지 처리 방법이 달라서 어느 쪽이 더 데이터 로딩 및 네트워크 요청에 적합한지 고민하다가 정리하게 되었다.
- 챗GPT에 검색한 내용을 함께 정리했다.
- 내용을 정리하고 나니 두 방법의 각각의 장단점을 고려해서 적용하려는 서비스에 따라 적절하게 선택할 필요가 있음을 배웠다.
1. 새 페이지 번호마다 API로 DB에 요청하기
- 방법 : 페이지 번호가 바뀔 때마다
OFFSET이 변경된 query문을 DB에 요청해서 새 데이터를 받아온 후 보여준다. - 장점
- 초기에 적은 양의 데이터를 받아오기 때문에 로딩 시간이 짧다.
- 데이터를 점진적으로 가져오고, 매번 요청을 보내기 때문에 최신 데이터를 반영해서 보여줄 수 있다.
- 단점
- 페이지 이동이나 스크롤을 할 때마다 네트워크 요청을 보내기 때문에 네트워크 요청이 증가한다.
- 아래 예시 코드는 챗GPT에서 페이지/스크롤이 넘어갈 때마다 새 데이터를 기존 데이터에 추가해서 보여주는 형식으로, 페이지마다 제한된 갯수를 출력하는 경우라면
setData(newData)로만 설정해도 작동되었다.
// chatgpt 예시코드
import React, { useState, useEffect, useRef } from 'react';
const App = () => {
const [data, setData] = useState([]);
const [page, setPage] = useState(1);
const [loading, setLoading] = useState(false);
const observerRef = useRef();
useEffect(() => {
fetchData(page); // 페이지가 바뀔 때마다 api 요청
}, [page]);
const fetchData = async (page) => {
setLoading(true); // 데이터 가져오기 전 로딩 처리
try { // 예시로 데이터를 가져오는 코드
const response = await fetch(`https://api.example.com/data?page=${page}&limit=10`);
const newData = await response.json();
setData(prevData => [...prevData, ...newData]); // 기존 데이터 + 새 데이터로 표시
} catch (error) {
console.error("Failed to fetch data:", error);
} finally {
setLoading(false);
}
};
const handleObserver = (entries) => { // 스크롤이 넘어가면 새 페이지로 처리
const target = entries[0];
if (target.isIntersecting) {
setPage(prevPage => prevPage + 1);
}
};
useEffect(() => {
const option = {
root: null,
rootMargin: "20px",
threshold: 1.0
};
const observer = new IntersectionObserver(handleObserver, option);
if (observerRef.current) observer.observe(observerRef.current);
return () => {
if (observerRef.current) observer.unobserve(observerRef.current);
};
}, []);
return (
<div>
<h1>Infinite Scroll with Intersection Observer</h1>
<div>
{data.map((item, index) => (
<div key={index} className="item">
{item.name}
</div>
))}
</div>
{loading && <p>Loading...</p>}
<div ref={observerRef} style={{ height: '20px', backgroundColor: 'lightgray' }} />
</div>
);
};
export default App;
2. 데이터를 먼저 받아온 후 Array.slice()로 처리하기
- 방법 : 데이터를 초기에 많이 받아온 후 사용자에게 보여줄 때
Array.slice(offset, length)로 가공하여 보여준다. - 장점
- 페이지 이동이나 스크롤로 새 데이터를 표시할 때 네트워크 요청이 필요 없다.
- 단점
- 초기에 데이터를 많이 받아오기 때문에 초기 로딩 시간이 길어진다.
- 데이터가 자주 변경되는 서비스에 적용할 경우 최신 데이터가 누락된 상태로 보여질 수 있다.
- 아래 예시 코드는 챗GPT로 작성된 코드다.
// chatgpt 예시 코드
import React, { useState, useEffect } from 'react';
const App = () => {
const [data, setData] = useState([]);
const [visibleData, setVisibleData] = useState([]);
const [page, setPage] = useState(1);
const itemsPerPage = 20;
useEffect(() => {
const fetchData = async () => {
// 한 번에 모든 데이터를 가져옴
const result = await fetch('https://api.example.com/data').then(res => res.json());
setData(result); // 데이터를 저장
setVisibleData(result.slice(0, itemsPerPage)); // 표시할 데이터를 따로 저장
};
fetchData();
}, []);
const loadMore = () => { // 더보기 처리
setPage(prevPage => {
const newPage = prevPage + 1; // 다음 페이지
const start = (newPage - 1) * itemsPerPage; // 데이터 시작점(offset)
const end = newPage * itemsPerPage; // 가져올 데이터 범위(length)
setVisibleData(prevData => [...prevData, ...data.slice(start, end)]); // 표시할 데이터를 수정
return newPage;
});
};
return (
<div>
<h1>Load More Example</h1>
<div>
{visibleData.map((item, index) => (
<div key={index} className="item">
{item.name}
</div>
))}
</div>
<button onClick={loadMore}>Load More</button>
</div>
);
};
export default App;