앞서 페이지네이션과 관련된 내용들을 정리한 이전 글에 이어서 현재 미션중인 스프린트에서 페이지네이션을 구현해보려고한다.
페이지네이션의 개념을 알고 시작하고 싶다면 아래 링크 참조
https://injaeee.tistory.com/19
아래 사진은 미션의 피그마이다.
아래 사진처럼 페이지네이션을 구현하려면 이전 글에서 더보기 버튼을 눌러가며 추가적으로 데이터를 가져왔던 방식과는 다르게 전체 데이터의 수를 받아와서 화면에 띄울 페이지버튼의 숫자를 계산하는 로직이 필요했다.
아래 사진은 이번 미션의 백엔드 주소인데 상품들을 GET하는 api에서 정렬기준(orderBy), 페이지 번호(page), 한 페이지 당 화면에 띄울 상품 수(pageSize)를 요청할 수 있는 쿼리가 존재했다.
백엔드 주소에 맞춰서 이런식으로 api를 요청하면 아래처럼 response가 왔다. 다행히 전체 데이터의 개수를 totalCount로 같이 보내주어서 페이지 버튼의 수를 계산하기 수월하였다!
api.js
const BASE_URL = 'https://panda-market-api.vercel.app';
export async function getProducts({ order = 'recent', page = 1, pageSize }) {
const query = `orderBy=${order}`;
const response = await fetch(`${BASE_URL}/products?${query}&page=${page}&pageSize=${pageSize}`);
const body = await response.json();
return body;
}
response
{
"list": [
{
"id": 22,
"name": "ee",
"description": "eeeeeeeeeeeeeeee",
"price": 4,
"tags": [
"44"
],
"images": [
"https://sprint-fe-project.s3.ap-northeast-2.amazonaws.com/Sprint_Mission/user/210/1718529146905/arrow_left-icon.svg"
],
"ownerId": 210,
"favoriteCount": 0,
"createdAt": "2024-06-16T09:12:27.057Z",
"updatedAt": "2024-06-16T09:12:27.057Z"
},
// . . . . . . . 총 17개의 데이터들이 있었음 코드가 너무 길어져서 생략
],
"totalCount": 17
}
구현할 item 페이지에서 데이터 배열들(list)과 데이터들의 총 개수(totalCount)를 받아낸다음 useState를 이용해 각각 담아주었다.
const handleLoad = async (orderQuery) => {
const { list, totalCount } = await getProducts(orderQuery);
setItem(list);
setTotalCount(totalCount);
}
이제 위해서 언급했던 총 페이지 수를 계산해주면 되는데 전체 컨텐츠 개수에서 한 페이지에 보여주고자 하는 컨텐츠의 개수 를 나누어주면 해결할 수 있다. 예시로 현재 totalCount는 17개(데이터의 총 개수)고 한 페이지에 10개씩 보여주면 되기에 ( 17 / 10 )를 해주면 화면에 띄울 페이지네이션의 페이지 수는 두 개만 필요한 것이다.
useEffect(() => {
setTotalPages(Math.ceil(totalCount / pageSize));
//Math.ceil(전체 컨텐츠 개수 / 한 페이지에 보여주고자 하는 컨텐츠의 개수)
}, [item])
마지막으로 현재 페이지를 나타내는 currentPage의 상태만 만들어주고, 페이지 버튼을 눌렀을 때 누른 페이지 번호에 맞게 currentPage상태를 변경해주는 버튼의 onClick이벤트를 만든다.
const [currentPage, setCurrentPage] = useState(1); //기본 페이지는 1로
const handlePageChange = (page) => {
setCurrentPage(page);
}
이제 페이지네이션에서 필요한 총 페이지의 수와 현재 페이지를 가르키는 상태, 버튼 이벤트까지 만들었으니 이것들을 페이지네이션 컴포넌트를 따로 만들어 Prop으로 넘겨준 다음 처리해주면 된다!
<PageNation totalPages={totalPages} currentPage={currentPage} handlePageChange={handlePageChange}></PageNation>
아래는 페이지네이션 컴포넌트의 코드이다. Prop으로 받은 totalPages만큼 map을 돌려 화면에 띄울 페이지번호 버튼들을 생성하고 각 버튼들의 클릭 이벤트로 Prop으로 받은 handlePageChange 이벤트 함수를 적절히 배치해준다.
currentPage를 이용해 각 버튼의 스타일이 현재 페이지면 css의 'active' 클래스를 입혀 파란색을 띄우게 하고 첫 페이지, 마지막 페이지일 때 '<' '>' 버튼이 비활성화 되도록 설정하였다.
PageNation.js
function PageNation({ totalPages, currentPage, handlePageChange }) {
return (
<div className="pagination">
<button className='pageButton' disabled={currentPage === 1} onClick={() => handlePageChange(currentPage - 1)}>{'<'}</button>
{Array.from({ length: totalPages }, (_, i) => (
<button
key={i + 1}
className={currentPage === i + 1 ? 'pageButton active' : 'pageButton'}
onClick={() => handlePageChange(i + 1)}
>
{i + 1}
</button>
))}
<button className='pageButton' disabled={currentPage === totalPages} onClick={() => handlePageChange(currentPage + 1)}>{'>'}</button>
</div>
)
}