api 요청은 아래와 같이 보내면 된다.
http://생략/api/members/myPage/products?page=0&size=10
페이지네이션을 클릭 시 클릭한 버튼의 value
값(1을 눌렀음 1을, 2를 눌렀음 2를)을 page=${value}
로 보내는 방법을 사용할 생각이다.
페이지네이션을 직접 개발할 수도 있겠지만 라이브러리를 사용해 보기로 했다. bootstrap은 부트캠프 당시 사용해본적이 있지만 mui는 사용해본적이 없어 mui pagination을 선택했다.
npm install @mui/material @emotion/react @emotion/styled
https://mui.com/material-ui/react-pagination/#main-content
mui 홈페이지에서 원하는 페이지네이션 코드를 긁어온다.
페이지네이션이 필요한 파일에 복사한 코드를 붙여넣기 한다.
프로젝트에선 내 정보 페이지의 "판매작품", "구매작품", "판매관리" 페이지에서 필요했기 때문에 각각의 페이지에서 불러와줬다.
import Pagination from "@mui/material/Pagination";
import Stack from "@mui/material/Stack";
export default function ProductstList() {
const [data, setData] = useState<ProductListType[]>([]);
// 페이지네이션
const [page, setPage] = useState(0);
const [totalPages, setTotalPages] = useState([]);
const handlePageChange = (e, value) => {
setPage(value - 1);
};
useEffect(() => {
const getData = async () => {
const res = await getProductsList(page);
setData(res.data);
setTotalPages(res.data.pageInfo);
};
getData();
}, [page]);
return (
<div className="flex justify-center mt-20">
{totalPages && (
<Stack spacing={2}>
<Pagination
count={totalPages.totalPages}
defaultPage={1}
shape="rounded"
size="large"
onChange={(e, value) => handlePageChange(e, value)}
defaultValue={1}
boundaryCount={2}
/>
</Stack>
)}
</div>
)
page
의 기본값을 0으로 설정한다.page=1
라고 요청 보낸다면 1페이지에 10개 데이터가 page=2
라고 요청 보냈을 때는 2페이지에 6개의 데이터가 들어올 것이라고 생각하게 된다. 하지만 page=1
라고 요청을 보내면 2페이지의 데이터 6개가 들어오게 된다. 확실하진 않지만 DB에 저장되는 값이 0부터 시작해서 그러는 것 같다. 그렇기 때문에 page
의 기본값은 0부터 시작하는 것으로 설정하였다.totalPages
에는 서버에서 보내주는 데이터에서 페이지에 대한 정보를 담고 있는 pageInfo
를 저장한다.setPage(value - 1)
페이지네이션을 클릭하면 handlePageChange
함수가 실행된다. 이때 value
값은 클릭한 페이지네이션 버튼의 값이다. 즉, 1을 클릭하면 value=1
이고, 3을 클릭했으면 value=3
이 된다. 위의page
에서 적었듯이 page
는 0부터 시작한다. 페이지네이션 버튼에는 0이 없고, 1부터 시작하기 때문에 원하는 페이지의 제대로된 정보를 불러오기 위해선 value
값에서 1을 빼줘야한다.페이지네이션에서 사용 가능한 props들은 아래 링크에서 확인할 수 있다.
https://mui.com/material-ui/api/pagination/
사용한 props들만 작성해보자면
count
: 총 페이지 갯수. useEffect
를 통해 데이터를 불러온 뒤totalPages
에 저장해두었던 값 중 totalPages
를 사용한다.defalutPage
: 기본적으로 선택되어 있는 페이지. 1로 설정해두었다.shape
: 페이지네이션 버튼의 모양을 어떻게 할 것인지. 'circular'와'rounded' 중 선택 가능하다.size
: 페이지네이션 컴포넌트의 크기를 어떻게 할 것인지.onChange
: 페이지가 변경되었을 때 사용되는 함수.defalutValue
: 처음과 끝에서 항상 표시되는 페이지의 수.데이터의 타입의 경우 아래와 같이 interface를 사용해 지정했다.
interface ProductListType {
data: ProductType[];
pageInfo: {
page: number;
size: number;
totalElements: number;
totalPages: number;
};
}
interface ProductType {
saleId: number;
sellerId: number;
productName: string;
period: {
startedAt: string;
endAt: string;
};
isDeleted: boolean;
isAlwaysOnSale: boolean;
createdAt: string;
}
페이지네이션 라이브러리 적용은 어렵지 않았다.
처음 작성했던 코드는 value
가 아니라 e.target.outerText
를 사용했었다. 그러다보니 -1를 줄여서 요청을 보낼 때 페이지 버튼을 누르면 정상적으로 작동했지만 양 옆의 < > 화살표 버튼을 누르면 e.target.outerText
가 NaN
이 되어버려 제대로 작동되지 않았었는데 value
를 사용해 손 쉽게 해결할 수 있었다.