리액트 페이지네이션 구현하기(React pagination) (2)
📘 페이지네이션 컴포넌트 만들기
페이지네이션을 구현하기 위해, 숫자 리스트를 표시하는 컴포넌트를 만들어 보겠습니다.
그 전에, App.js에서 페이지네이션 관련 변수들과 함수를 정의하겠습니다.
📜 App.js 수정
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
import "./App.css";
import React, { useState, useEffect } from "react";
import axios from "axios";
import Posts from "./Posts";
import Pagination from "./Pagination";
function App() {
const [posts, setPosts] = useState([]);
const [loading, setLoading] = useState(false);
const [currentPage, setCurrentPage] = useState(1);
const [postsPerPage, setPostsPerPage] = useState(10);
useEffect(() => {
const fetchData = async () => {
setLoading(true);
const response = await axios.get(
"https://jsonplaceholder.typicode.com/posts"
);
setPosts(response.data);
setLoading(false);
};
fetchData();
}, []);
/* 새로 추가한 부분 */
const indexOfLast = currentPage * postsPerPage;
const indexOfFirst = indexOfLast - postsPerPage;
const currentPosts = (posts) => {
let currentPosts = 0;
currentPosts = posts.slice(indexOfFirst, indexOfLast);
return currentPosts;
};
/* */
return (
<div className="App">
<Posts posts={currentPosts(posts)} loading={loading}></Posts>
<Pagination
postsPerPage={postsPerPage}
totalPosts={posts.length}
paginate={setCurrentPage}
></Pagination>
</div>
);
}
export default App;
- 총 데이터를 postsPerPage 만큼 등분해서 보여줍니다.
- 현재 예시에서는 총 100개의 데이터를 10등분해서, 1~10까지 보여주고, 그 다음 11~20까지 보여주고, 그 다음 21~30, … 이렇게 배열의 데이터를 나누어서 보여주어야 합니다.
이를 위해 indexOfLast, indexOfFirst 변수를 선언합니다.
- 이후 해당 페이지의 첫 번째와 마지막 인덱스 번호 값을 구합니다.
- 예를 들어, 첫 번째 페이지의 가장 처음 인덱스는 1번이고, 마지막은 10번이 됩니다. 두 번째 페이지는 11번 ~ 20번이 됩니다.
처음과 끝 인덱스 번호를 구한 다음,
currentPosts
함수를 통해, 100개의 배열 데이터를slice
함수로 분할해 줍니다. 이후 분할된 새로운 배열을 리턴합니다.slice
함수는 begin, end 값을 인자로 넘겨받아 배열의begin
번째 ~end-1
번째 까지의 복사본을 새롭게 반환해 주는 함수입니다. 페이지네이션을 구현할 때 적합하다고 볼 수 있습니다.
- return 문 안에서
<pagination>
로 컴포넌트를 새로 사용하였습니다.import Pagination from './Pagination';
을 적고 사용합니다. 이 때, 여기에 인자로postsPerpage, totalPosts, paginate
를 넘깁니다. 각각 페이지 당 포스트 수, 전체 포스트 갯수,currentPage
상태를 변경하는 setter 함수 를 넘깁니다. - 사용자가 선택한 페이지 넘버에 따라,
currentPage
의 값이 변경되도록 구현할 것입니다. 예를 들어 사용자가 3번을 선택하면,currentPage
상태값을 사용한indexOfLast
,indexOfFirst
변수의 값도 변경되면서 분할되는 데이터들도 달라질 것입니다. 따라서setCurrentPage
함수를 Pagination 컴포넌트에 인자로 넘긴 것입니다.- 즉,
useState
로 상태값을 만들고, 해당 상태값을 변경하는 setter 함수를 활용한 것입니다.
- 즉,
📜 Pagination.js 생성 및 작성
페이지 리스트를 보여 줄 컴포넌트를 작성합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
import React from "react";
import styled from "styled-components";
const PageUl = styled.ul`
float: left;
list-style: none;
text-align: center;
border-radius: 3px;
color: white;
padding: 1px;
border-top: 3px solid #186ead;
border-bottom: 3px solid #186ead;
background-color: rgba(0, 0, 0, 0.4);
`;
const PageLi = styled.li`
display: inline-block;
font-size: 17px;
font-weight: 600;
padding: 5px;
border-radius: 5px;
width: 25px;
&:hover {
cursor: pointer;
color: white;
background-color: #263a6c;
}
&:focus::after {
color: white;
background-color: #263a6c;
}
`;
const PageSpan = styled.span`
&:hover::after,
&:focus::after {
border-radius: 100%;
color: white;
background-color: #263a6c;
}
`;
const Pagination = ({ postsPerPage, totalPosts, paginate }) => {
const pageNumbers = [];
for (let i = 1; i <= Math.ceil(totalPosts / postsPerPage); i++) {
pageNumbers.push(i);
}
return (
<div>
<nav>
<PageUl className="pagination">
{pageNumbers.map((number) => (
<PageLi key={number} className="page-item">
<PageSpan onClick={() => paginate(number)} className="page-link">
{number}
</PageSpan>
</PageLi>
))}
</PageUl>
</nav>
</div>
);
};
export default Pagination;
숫자가 나타나는 컴포넌트에 약간의 css를 첨가해 보았습니다. styled-components를 활용한 것입니다. 이를 활용해 스타일 적용 자체도 컴포넌트를 작성하듯이 할 수 있습니다.
중요한 코드는 하단의 const Pagination
~ 부터입니다.
- Pagination 컴포넌트는 postsPerPage, totalPosts, paginate 를 인자로 넘겨받았습니다.
pageNumbers
의 경우, 총 페이지 넘버 수를 계산한 뒤 웹 페이지에서 보여주기 위하여, 전체 포스트 갯수를 페이지 당 포스트 갯수로 나눈 값으로 배열을 만든 것입니다.- 포스트 개수가 100개이고, 페이지 당 포스트 개수를 10개로 지정할 경우
1 2 3 4 5 6 7 8 9 10
이 생성될 것입니다.
- 포스트 개수가 100개이고, 페이지 당 포스트 개수를 10개로 지정할 경우
- return문 내부를 보겠습니다.
- 앞서 구한
pageNumbers
배열을 map 함수를 이용해 요소 하나씩 꺼내면서<li>
로 만들고 클릭 이벤트를 걸어 주었습니다. - 이 때
<li>
하위에<span>
을 만들어 거기에 숫자를 표시했고({number}
),<span>
에onClick
이벤트를 작성하였습니다. 화살표 함수로 작성한 것이며,onClick={() => paginate(number)}
부분에서paginate 함수
는 앞서 받은setCurrentPage
함수이며, 클릭할 때 setCurrentPage 함수의 인자로 number를 넘겨currentPage
상태값을 변경하는 것을 구현한 것입니다. - 따라서 사용자가 숫자를 클릭하면,
currentPage
상태값이 변경되고, 이에 따라 App.js에서 작성한 대로 배열 데이터 값이 분할되어 화면에 표시될 것입니다.
- 앞서 구한
이제 다 왔습니다! 실행해 보면 아래와 같이 표시될 것입니다.
실제로 리액트 프로젝트를 통해 웹 페이지를 만들 때, 다량의 데이터를 가져온 다음 간편하게 페이지네이션을 작성하는 방법에 대하여 알아보았습니다.
이것을 진행하면서 중요하게 짚고 가야 할 것들에는 useEffect
, useState
등의 hook 사용과, async, await, axios
등으로 데이터를 가져오는 방법들 이라고 생각합니다.