TFT 전적 사이트를 개발 중에 랭킹 페이지를 만들면서 pagination 기능이 필요하여
https://www.youtube.com/watch?v=IYCa1F-OWmk 해당 링크를 참조하여 직접 구현 해 보았습니다.
우선 컴포넌트 상태 관리를 위해 useState를 사용했습니다.
posts는 전체 데이터, currentPage는 현재 페이지, postsPerPage는 한 페이지에서 보여줄 post의 수 를 나타냅니다.
useEffect를 통해 컴포넌트가 처음 렌더링될 때 posts 데이터를 요청해 상태에 저장했습니다.
const App = () => {
const [posts, setPosts] = useState([]);
const [loading, setLoading] = useState(false);
const [currentPage, setCurrentPage] = useState(1);
const [postsPerPage] = useState(10);
useEffect(() => {
const fetchPosts = async () => {
setLoading(true);
const res = await =axios.get("https://jsonplaceholder.typicode.com/posts");
setPosts(res.data);
setLoading(false);
};
fetchPosts();
}, []);
return(
<div>hi</div>
)
}
indexOfLastPost는 해당 페이지에서 마지막 post의 index 번호를 가르킵니다.
indexOfFirstPost는 해당 페이지에서 첫번째 post의 index 번호를 가르킵니다.
currentPosts는 각 페이지에서 보여질 포스트 배열입니다.
const indexOfLastPost = currentPage * postsPerPage;
const indexOfFirstPost = indexOfLastPost - postsPerPage;
const currentPosts = posts.slice(indexOfFirstPost, indexOfLastPost);
App.js에서 Posts 컴포넌트를 불러와 posts, loading state를 전달했습니다.
import Posts from "./components/Posts";
...
return (
<div className="container">
<Posts posts={currentPosts} loading={loading} />
<Pagination postsPerPage={postsPerPage} totalPosts={posts.length} paginate={paginate} />
</div>
);
Posts 컴포넌트입니다. 부모 컴포넌트로부터 posts, loading props를 전달받아
map 메소드를 사용하여 post를 렌더링합니다.
import React from "react";
const Posts = ({ posts, loading }) => {
if (loading) {
return <h2>Loading...</h2>;
}
return (
<ul className="list">
{posts.map((post) => (
<li key={post.id} className="list_item">
{post.title}
</li>
))}
</ul>
);
};
export default Posts;
postsPerPage 값이 10이므로 한 페이지에서 10개의 post를 보여줍니다.
App.js에서 Pagination 컴포넌트를 불러와 postsPerPage, totalPosts, paginate props를 전달했습니다.
totalPosts는 전체 post의 개수, paginate 함수는 현재 페이지 번호(currentPage)를 설정하는 함수입니다.
import Pagination from "./components/Pagination";
...
const paginate = (pageNumber) => setCurrentPage(pageNumber);
...
return (
<div className="container">
<Posts posts={currentPosts} loading={loading} />
<Pagination postsPerPage={postsPerPage} totalPosts={posts.length} paginate={paginate} />
</div>
);
}
Pagination 컴포넌트입니다.
pageNumber ( 전체 페이지 수 / 각 페이지 당 포스트 수) 를 계산하여 전체 페이지 번호를 구한 배열입니다.
페이지 번호를 렌더링하고 onClick 속성에 paginate 함수를 이벤트로 등록하였습니다.
이제 페이지 번호를 누르면 paginate 함수에 의해서 현재 페이지(currentPage) 상태 값이 변경되고 현재 페이지에 해당하는 post들이 렌더링 됩니다.
import React from "react";
const Pagination = ({ postsPerPage, totalPosts, paginate }) => {
const pageNumber = [];
// Math.ceil: 올림
for (let i = 1; i <= Math.ceil(totalPosts / postsPerPage); i++) {
pageNumber.push(i);
}
return (
<ul className="pagination">
{pageNumber.map((pageNum) => (
<li
key={pageNum}
className="pagination_item"
onClick={() => paginate(pageNum)}
>
{pageNum}
</li>
))}
</ul>
);
};
export default Pagination;
TFT 전적 사이트 프로젝트에 적용해보았습니다.