세상에 존재하는 홈페이지는 다양하고, 게시판의 종류도 헤아릴 수 없을 만큼 많지만 대부분의 게시판들이 공통된 기능 하나를 제공하고 있다. 바로 페이지네이션.
게시글이 많을 경우에 한 화면에 모든 내용을 다 출력할 수가 없다. 이들을 출력할 공간도 없고 많은 데이터를 가져오데 필요한 자원과 시간이 너무 많이 필요하기 때문이다. 결국 한 화면에서 출력할 내용을 적절하게 끊어줄 필요가 있고, 다른 내용이 출력되도록 전환시켜주는 기능 또한 필요하다.
페이지네이션 기능 구현에는 다음과 같은 요소들이 필요하다.
지금 화면에서는 어떤 부분을 출력해야 하는지 알려주는 기준점.
한 화면에 표시될 내용의 갯수.
전체 데이터에서 어디부터 어디까지 가지고 와야하는지 알려주는 기준점.
전체 데이터의 길이.
const [currentPage, setCurrentPage] = useState(1);
const itemsPerPage = 12;
const lastItemIndex = currentPage * itemsPerPage;
const firstItemIndex = lastItemIndex - itemsPerPage;
const [dataLangth, setDataLangth] = useState(0);
이상의 정보들이 있으면 다음과 같이 페이지네이션 기능을 구현할 수 있다.
전체 데이터의 길이와 한 화면에 표시될 내용의 갯수를 이용하여, 해당 게시글은 몇 페이지까지 있는지 표현할 수 있다.
전체 데이터에서 어디부터 어디까지 가지고 와야하는지 알려주는 기준점을 이용하여 전체 데이터에서 한 페이지에 출력할 내용만 가져올 수 있다.
오라클 혹은 MySQL같은 RDBMS들은 각각의 데이터를 자체적인 index를 더하여 관리할 수 있다. 따라서 애초에 데이터를 조회해 올 때 어디부터 어디까지만 가져오라고 지정할 수 있는 반면에, 파이어베이스는 그것이 불가능하다! 각 데이터 문서에 index가 존재하지 않기 때문. (id값을 숫자로 지정해줄 수는 있는데, 말 그대로 문서 id값을 숫자로만 만들어주는 것이고 파이어베이스에서 지원하는 방식이 아니라서 몇 번부터 몇 번까지 문서를 가지고 오라고 할 수가 없다.)
파이어베이스에서는 모든 데이터를 프론트까지 가지고 온 다음에 필요한 만큼 나누어서 화면에 출력하거나, 커서 페이징이라고 하여 쿼리 함수를 통해 일정 갯수의 데이터만을 가지고 온 다음에 해당 데이터의 가장 마지막 문서를 기준점으로 '다음 페이지 넘어가기' 기능 정도는 구현이 가능하지만 페이지를 번호 순서로 나누고 몇 번 페이지로 바로 이동한다는 등의 기능 구현이 불가능하다. (구현을 위해서는 외부 라이브러리를 사용해야 한다.)
이번 프로젝트에서는 전자의 방법을 선택하여 기능을 구현하였다. 프론트단에서 이미 모든 데이터를 가지고오는 것이기 때문에 자원 낭비가 극심하지만 일단 페이지네이션 기능이 정상적으로 동작하도록 만드는 것을 우선 목표로 잡았다.
페이지네이션 기능의 구현 자체는 게시글 목록 조회 기능의 변형일 뿐이다. 프론트에 출력할 데이터 배열의 형태만 달라질 뿐.
setData(mappingData.slice(firstItemIndex, lastItemIndex));
페이지네이션 사용시에는 반환된 데이터를 slice 함수를 이용해 한 페이지에서 출력할 부분만 잘라서 setState하도록 한다.
코드의 재사용성을 위해 페이지네이션 기능 구현은 독립된 컴포넌트를 사용하도록 하였다.
<Pagination
postsPerPage={itemsPerPage}
totalPosts={dataLangth}
paginate={setPageNumber}
/>
페이지네이션 컴포넌트의 역할은 필요한 데이터를 props로 받아서 전체 페이지 갯수에 따라 페이지 버튼을 생성하고, 버튼을 클릭했을 때는 지금 화면에서는 어떤 부분을 출력해야 하는지 알려주는 기준점을 갱신해주는 것이다.
import '../styles/Pagination.css';
import React from 'react';
const Pagination = ({ postsPerPage, totalPosts, paginate }) => {
// 1페이지부터 끝 페이지까지의 숫자를 저장할 빈 배열.
const pageNumbers = [];
// 전체 게시글의 숫자와 페이지당 게시글 숫자를 받아와서..
// 계산하여 페이지는 몇 페이지까지 나오는지를 계산한 다음..
// 소수점을 올림처리하여 정수로 맞추고 그 횟수만큼 빈 배열에 숫자를 저장.
for (let i = 1; i <= Math.ceil(totalPosts / postsPerPage); i++) {
pageNumbers.push(i);
}
// 그리고 빈 배열에 채워진 숫자만큼 map 함수로 풀어 출력한다.
// 페이지 하나당 버튼 하나를 만들고 현재 페이지가 몇 페이지인지 등록하는 함수를 연결.
return (
<div className='paganation-outer'>
{pageNumbers.map(number => (
<div className='paganation-btu' key={number}>
<button className='paganation-button gifont' onClick={() => paginate(number)}>{number}</button>
</div>
))}
</div>
);
};
export default Pagination;
기능을 테스트하니.. 잘 동작한다.
평가 방법, 개인적인 코드 리뷰 및 Chat GPT 사용.
-> 데이터 유효성을 확인하지 않음. 입력한 값이 정상적인지 검사하는 유효성 검사와 정상적인 데이터 형식을 지켰는지 확인하는 절차가 존재하지 않음. 페이지네이션 기능에 필요한 요소들의 값이 잘못되었을 경우에 대한 예외 처리가 존재하지 않음.
-> 부가 기능 필요. 이전 페이지, 다음 페이지 등의 버튼을 추가하여 사용자 편의점을 높일 필요가 있음.
정말 좋은 정보 감사합니다!