이번에는 MUI의 Pagination 컴포넌트를 사용해서 페이지네이션을 구현해 보았다.
ThemeProvider를 통해 스타일도 커스텀해 보았다.
React Pagination component - Material UI
The Pagination component enables the user to select a specific page from a range of pages.
mui.com
↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑
참고했던 것
// theme.ts
import { createTheme } from "@mui/material/styles";
const theme = createTheme({
breakpoints: {
values: {
xs: 0, // 모바일
sm: 600, // 기존 small
md: 769, // 새로운 breakpoint 추가!
lg: 900, // 기존 medium
xl: 1200, // 기존 large
},
},
});
export default theme;
MUI는 Tailwind CSS와 breakpoint가 달랐다.
그래서 똑같은 md여도 tailwind는 768 이상이고 MUI는 900 이상...
스타일이 안 맞아서 createTheme()으로 bp를 새로 추가해 주었다.
이렇게 커스텀한 스타일은 ThemeProvider로 Pagination 컴포넌트를 감싸면 Pagination에 적용이 가능하다.
"use client";
import { ReactNode, useState } from "react";
import { Pagination, ThemeProvider } from "@mui/material";
import theme from "./theme";
interface PaginationsProps {
children: ReactNode; // children으로 컴포넌트 받을 예정
}
// ✅ 더미 데이터 (1920개의 아이템)
const allItems = Array.from({ length: 1920 }, (_, i) => `Item ${i + 1}`);
const PaginationList: React.FC<PaginationsProps> = ({ children }) => {
const [page, setPage] = useState(1); // 현재 페이지
const itemsPerPage = 8; // 한 페이지에 보여줄 개수
// 더미데이터가 현재 배열이므로 인덱스 사용
// 페이지 1 → startIndex = 0, endIndex = 8 → Item 1 ~ Item 8
// 페이지 2 → startIndex = 8, endIndex = 16 → Item 9 ~ Item 16
const startIndex = (page - 1) * itemsPerPage;
const endIndex = startIndex + itemsPerPage;
const displayedItems = allItems.slice(startIndex, endIndex);
// 페이지 변경 핸들러
const handleChange = (event: React.ChangeEvent<unknown>, value: number) => {
setPage(value); // 클릭된 페이지를 현재 페이지로 업데이트
};
return (
<ThemeProvider theme={theme}>
{/* 현재 페이지의 데이터 렌더링 */}
{displayedItems.map((item, index) => (
<div key={index}>
{item} {/* 임시 */}
{children}
</div>
))}
{/* ✅ 페이지네이션 UI */}
<Pagination
count={Math.ceil(allItems.length / itemsPerPage)} // 전체 페이지 개수 (전체 아이템 / 페이지 당 아이템)
page={page}
onChange={handleChange}
sx={{
"& .MuiPaginationItem-root": {
fontFamily: "var(--font-nanumsquare)",
color: "#6A6A6A", // 기본 페이지 텍스트 색상: main-text
fontSize: { xs: "12px", md: "16px" },
margin: "0 2px",
},
"& .MuiPaginationItem-root:hover": {
backgroundColor: "#ffd69588", // bg-yellow-1에 투명도 적용
},
"& .MuiPaginationItem-page.Mui-selected:hover": {
backgroundColor: "#ffd69588",
},
"& .MuiPaginationItem-page.Mui-selected": {
backgroundColor: "#FFE7BF", // bg-yellow-2
border: "1px solid #EFC071", // main-yellow
}, // 선택된 페이지 색상
"& .MuiPaginationItem-previousNext": { color: "#EFC071" }, // 이전/다음 버튼 색상
}}
className="pt-4"
/>
</ThemeProvider>
);
};
export default PaginationList;
interface PaginationsProps {
children: ReactNode; // `children`으로 컴포넌트를 받을 예정
}
Swiper 라이브러리 사용 때와 똑같이 Props 타입을 먼저 지정해 주었다.
컴포넌트를 페이지네이션 할 거니까 ReactNode로!
const [page, setPage] = useState(1); // 현재 페이지 상태
const itemsPerPage = 8; // 한 페이지에 보여줄 개수
현재 페이지를 상태로 관리하고, 한 번에 8개의 아이템을 표시하도록 설정했다.
(생각해보니 페이지마다 표시하기로 한 아이템 수가 달라서, 이것도 따로 props로 받아주어야 할 것 같다. 수정해야지)
const allItems = Array.from({ length: 1920 }, (_, i) => `Item ${i + 1}`);
그리고 확인을 위해 더미 데이터를 생성했다.
const startIndex = (page - 1) * itemsPerPage; // 시작 인덱스
const endIndex = startIndex + itemsPerPage; // 끝 인덱스
const displayedItems = allItems.slice(startIndex, endIndex);
그리고 slice()를 통해 현재 페이지에서 보여줄 데이터만 잘라서 가져오도록 했다.
페이지 1 → startIndex = 0, endIndex = 8 → Item 1 ~ Item 8
페이지 2 → startIndex = 8, endIndex = 16 → Item 9 ~ Item 16
요렇게 된다.
const handleChange = (event: React.ChangeEvent<unknown>, value: number) => {
setPage(value);
};
클릭된 페이지 값을 setPage(value)로 업데이트 한다.
page가 바뀌면 선택한 페이지에 맞게 displayedItems가 자동으로 변경된다!
{displayedItems.map((item, index) => (
<div key={index}>
{item} {/* 현재 페이지의 아이템 표시 */}
{children} {/* children을 포함하여 추가적인 UI 렌더링 가능 */}
</div>
))}
아까 만든 더미 데이터를 map()을 사용해서 렌더링 한다.
{children}을 추가해서 외부에서 받아온 컴포넌트가 각 아이템 아래 렌더링 되도록 했다.
<Pagination
count={Math.ceil(allItems.length / itemsPerPage)} // 전체 페이지 개수
page={page} // 선택된 페이지
onChange={handleChange} // 클릭 시 페이지 변경
sx={{ // 스타일
"& .MuiPaginationItem-root": {
fontFamily: "var(--font-nanumsquare)",
color: "#6A6A6A",
fontSize: { xs: "12px", md: "16px" },
margin: "0 2px",
},
"& .MuiPaginationItem-root:hover": {
backgroundColor: "#ffd69588",
},
"& .MuiPaginationItem-page.Mui-selected:hover": {
backgroundColor: "#ffd69588",
},
"& .MuiPaginationItem-page.Mui-selected": {
backgroundColor: "#FFE7BF",
border: "1px solid #EFC071",
},
"& .MuiPaginationItem-previousNext": { color: "#EFC071" },
}}
className="pt-4"
/>
이것도 그냥 하라는대로 하면 된다.
마찬가지로 스타일에 들어가는 클래스명은 기본 제공되는 거다!
지금은 더미 데이터지만 API 데이터를 받아와서 넣어줄 예정이다.
'개발 > 프로젝트' 카테고리의 다른 글
Zustand로 API 호출 및 상태 관리하기 (0) | 2025.02.28 |
---|---|
Tailwind CSS + SCSS로 반응형 구현하기 (0) | 2025.02.25 |
Swiper.js 라이브러리를 사용해서 슬라이더 구현하기 (Next.js + React) (0) | 2025.02.13 |
자동 로그인 구현하기 (0) | 2025.01.12 |
Next.js에서 RTK Query로 카카오 로그인 구현하기 (1) | 2025.01.09 |