REACT 페이징 구현하기(페이징 양식, 코드) 부제 : REACT 페이징에 관하여

작성자 : 조회수 :


간단한 알고리즘을 통해서 배우는데

저는 일단 컴포넌트화 해서 이번 포트폴리오 때 계속 재사용 예정이라 그것을 염두하고 설계 하겠습니다.

 

전에 했지만 그래도 다시 페이징 할 때 사용할 알고리즘을 정리해보겠습니다.

예를 들어보면 57개의 글 목록을 받았을 때

 

한 페이지에 10개씩 보여준다고 했다면 총 6페이지가 되고 마지막 페이지는 7개의 글만 나올 것입니다.



크게 두 구역을 생각하면 됩니다.

 

State를 먼저 생각해보겠습니다.



구현해야 할 목록

 

1.     한 페이지당 몇 개의 글을 보여줄 것 인가.

2.     최대 페이지 버튼은 몇 개로 지정할 것 인가.

3.      

 

TotalPost => 받아온 총 게시판 글들

ViewNumber => 한 페이지에 보여줄 게시판 글

Page => 현재 페이지 (기본 1)

                       

그리고 Pagenaition의 페이지 번호는 10(얼마든지 변경가능)개를 넘을 시 다음 버튼을 통해

 

예를 들어 1,2,3,4,5,6,7,8,9,10 이고 Page10을 넘어가거나 다음버튼을 눌렀을 때

 

다음 11,12,13,14,15,16,17,18,19,20 이런 식으로 넘어가게끔 보여줍니다.

 

slice함수와 map 함수를 사용해서 간단하게 만들어 봅니다.








PostLength : axiosajax든 가져온 게시판 배열 길이를 그대로 넣어줍니다.

oneViewNumber  : 한페이지에 몇 개를 보여줄지 정해주는 글 입니다.=

page : state를 사용했습니다. 현재 페이지가 언제인지 나타냅니다.

setPage : page state set state를 말합니다.

inMaxPageListNumber : 페이지 버튼을 몇 개를 보여줄지 정해주는 숫자입니다.



위의 사진처럼 Page를 그대로 받은 상태이기 때문에 다음버튼을 누르거나

 

현재 버튼을 눌렀을 때 setPage(i)값이거나 +1 해주면 됩니다.


정말 중요한 점 





useEffect를 사용하고 감지는 page의 값 변경을 감지로 두는 게 이 코드에 가장 중요한 부분입니다.

 

setState를 마치더라 하더라도 리액트는 개발자가 원하는 대로 바로 state변경, 즉 자주 변경하는 걸 싫어하기에

 

동작하지 않을 수 있습니다. 그럴 때 마다 useEffect를 이용해서 state변경이 감지 될 때 제가 생각해놓은

 

페이징 알고리즘을 바로바로 실행해서 resultList의 값이 변경 되도록 만들어 줍니다. 알고리즘은 대략 이렇습니다.

예를 들어

 

총 게시물 320

 

원하는 페이지 10 n

현재 페이지 p

페이지 네이션의 페이지 pp

 

총 나온 페이지 수

 

320 / 10 = 32페이지 나옴

 

그럼 여기서 원하는 페이지는 10 이니

 

1~10

11~20

21~30

31~32

 

이렇게 페이징됩니다.

p = 1

 

기존 페이지에 원하는 범위의 숫자를뺌

 

ex>

n 10

p = 22

그럼 if p-n 을 두번해야 p < n이됨 그럼 페이지가 2페이지라는걸 알게됨

 

그럼 2페이지니깐 pp라는걸 알게됨

 

그래서 공식은 pp(=2)*n ~ n*pp + n을 한번더

 

1*10  1+n*pp(0) ~ n * (pp+1)

11~20 1+n*pp(1) ~ n * (pp+1)

21~30 1+n*pp(2) ~ n * (pp+1)

31~32 1+pp*n ~ n+=n

 

이렇게 진행됩니다.








결과는 이렇게 나오며 하나에 10개의 글이 나오지만 너무 큰  바람에 이렇게 담아넣습니다.


코드

ListPageNation.jsx
import axios from "axios";
import { React, useState, useEffect } from "react";
import "bootstrap/dist/js/bootstrap.bundle";
export default function ListPageNation({
postLength, // 포스트 배열의 길이 (게시판 길이)
oneViewNumber, // 한 페이지의 보여줄 Number
page, // 현재페이지
setPage,
inMaxPageListNumber, // 예 10이면) 페이지 몇개 이전 1,2,3,4,5,6,7,9,10 다음
}) {
const [numPages, setNumPages] = useState(
Math.ceil(postLength / oneViewNumber)
);
const middleList = Array(numPages)
.fill()
.map((v, i) => i + 1);
const [start, setStart] = useState(0);
const [end, setEnd] = useState(inMaxPageListNumber);
const [resultList, setResultList] = useState(middleList.slice(start, end));
useEffect(() => {
// 얼마나 반복했는지 횟수 알기위함
// 즉 현재 페이지, page의 page라 해서 pp
var fpage = page;
var fInMaxPageListNumber = inMaxPageListNumber;
var start = 0;
var end = inMaxPageListNumber;
var pp = 0;
while (fpage > fInMaxPageListNumber) {
fpage = fpage - fInMaxPageListNumber;
pp++;
if (fpage < fInMaxPageListNumber) {
break;
}
}
// 페이지가 도출됨
start = inMaxPageListNumber * pp + 1;
end = inMaxPageListNumber * (pp + 1);
setStart(start);
setEnd(end);
setResultList(middleList.slice(start - 1, end));
}, [page]);
return (
<ul className="pagination mt-5 justify-content-center">
<li className="page-item">
<button
className="page-link"
aria-label="Next"
onClick={() => {
setPage(1);
}}
disabled={page === 1}
>
<span aria-hidden="true">처음span>
button>
li>
<li className="page-item">li>
<button
className="page-link"
aria-label="Previous"
onClick={() => {
setPage(page - 1);
}}
disabled={page === 1}
>
<span aria-hidden="true">이전span>
button>
{resultList.map((i) => (
<li key={i} className="page-item">
<button
className="page-link"
key={i}
onClick={() => {
setPage(i);
}}
aria-current={page === i ? "page" : null}
>
{i}
button>
li>
))}
<li className="page-item">
<button
className="page-link"
aria-label="Next"
onClick={() => {
setPage(page + 1);
}}
disabled={page === numPages}
>
<span aria-hidden="true">다음span>
button>
li>
<li className="page-item">
<button
className="page-link"
aria-label="Next"
onClick={() => {
setPage(numPages);
}}
disabled={page === numPages}
>
<span aria-hidden="true">마지막span>
button>
li>
ul>
);
}

 

 

 

 

 

 

 

 

이건 Post slice해주는 파일 입니다.

 MainAnnouncement.jsx

import "bootstrap/dist/js/bootstrap.bundle";
import axios from "axios";
import { React, useState, useEffect } from "react";
import { Link } from "react-router-dom";
import BoardBlock from "./AnnouncementComponents/BoardBlock";
// 내가 직접만든 페이지네이션 양식
import ListPageNation from "../../components/PageNation/ListPageNation";
export default function MainAnnouncement(props) {
const [announcementList, setList] = useState([]); // 빈 배열
// 게시판 단순 페이징
const [oneViewNumber, setOneViewNumber] = useState(10);
const [page, setPage] = useState(1);
const offset = (page - 1) * oneViewNumber;
const adminIn = localStorage.getItem("adminSuccess", "imadmin");
// 여긴 페이징 안의 페이징
// 페이징
const [pageNationPage, setPageNationPage] = useState(1);
const pageNationOffset = (pageNationPage - 1) * oneViewNumber;
useEffect(() => {
// 자동적으로 리스트 반환
const requestList = axios
.get("/find-all-announcement-board")
.then((res) => {
setList(res.data.reverse());
})
.catch((Error) => {
console.log(Error);
});
}, []);
return (
<div className="container mt-5">
{announcementList.length === 0 && <div>공지글이 없습니다div>}
{announcementList.length > 0 &&
announcementList
.slice(offset, offset + oneViewNumber)
.map((announcement) => {
return (
<BoardBlock
announcement={announcement}
key={announcement.id}
>BoardBlock>
);
})}
{announcementList.length > 0 && (
<ListPageNation
postLength={announcementList.length}
oneViewNumber={oneViewNumber}
page={page}
setPage={setPage}
inMaxPageListNumber={10}
/>
)}
{!!adminIn && (
<Link className="btn btn-dark" to="/announcement-write">
글쓰기
Link>
)}
div>
);
}


 

 

최대한 다른 분들이 편하게 볼 수 있도록 노력했지만 조금 더 글쓰기 실력을 늘리거나

 

다듬는 게 필요할 것 같습니다.

 

더 나은 글로 찾아오겠습니다. 감사합니다.

 

참고

 

- https://www.daleseo.com/react-pagination/

-