๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
Web Programming/React.js

[React.js] React์—์„œ ํŽ˜์ด์ง€๋„ค์ด์…˜ ๊ตฌํ˜„ํ•˜๊ธฐ

by Haren 2023. 10. 18.

๐Ÿง‘๐Ÿป‍๐Ÿ’ป ๊ทธ๋Ÿฐ ์š•์‹ฌ์ด ๋“ค ๋•Œ๊ฐ€ ์žˆ๋‹ค.

๋Œ€ํ•™๊ต ์กธ์—… ํ•™๊ธฐ, ํ˜„์žฅ ๊ฐœ์„  ์บก์Šคํ†ค ๋””์ž์ธ ์ˆ˜์—… (์ผ๋ช… ์กธ์—…์ž‘ํ’ˆ)์„ ๋“ฃ๊ณ  ์žˆ๋‹ค.

 

ํŒ€์žฅ์„ ๋งก์•„์„œ ์šฐ๋ฆฌ ๋Œ€ํ•™์˜ ์ทจ์—… ์—ญ๋Ÿ‰ ๊ฐ•ํ™” ํ”„๋กœ๊ทธ๋žจ ์ ์ˆ˜๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•˜๋Š” ๋žญํ‚น ์ปค๋ฎค๋‹ˆํ‹ฐ ์‚ฌ์ดํŠธ๋ฅผ ๊ฐœ๋ฐœํ•˜๊ณ  ์žˆ๋Š”๋ฐ, ์‚ฌ์šฉ์ž๋“ค์˜ ๋žญํ‚น์„ ๋ณด์—ฌ์ค„ ๋•Œ ํ•œ ํŽ˜์ด์ง€์— 30๊ฐœ์˜ ๋ฐ์ดํ„ฐ๋งŒ ๋ณด์—ฌ์ฃผ๊ณ  ์‹ถ์—ˆ๋‹ค. ๋ชปํ•ด๋„ ์ „์ฒด ์žฌํ•™์ƒ ์ˆ˜๊ฐ€ 1,000๋ช…์€ ์กฑํžˆ ๋„˜์„ ๊ฒƒ์ด๋ฏ€๋กœ ํ•œ ํŽ˜์ด์ง€๋งŒ์œผ๋กœ ๋žญํ‚น์„ ๋ณด์—ฌ์ฃผ๊ธฐ์—๋Š” ๊ฐ€๋…์„ฑ์ด ๋–จ์–ด์ง€๋‹ˆ๊นŒ.

 

๊ทธ๋ž˜์„œ ํŽ˜์ด์ง€๋„ค์ด์…˜ ์ฒ˜๋ฆฌ๊ฐ€ ํ•„์š”ํ–ˆ๋Š”๋ฐ, ๋ฐฑ์—”๋“œ๋ฅผ ๊ฐœ๋ฐœํ•˜๋Š” ํŒ€์›์—๊ฒŒ ๋ถ€ํƒํ•˜๊ธฐ์—๋Š” ์ด๋ฏธ ๊ทธ๊ฐ€ ๋งŒ๋“ค์–ด ์ฃผ๊ธฐ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๊ณ  ์žˆ๋Š” ์ˆ˜๋งŽ์€ API๊ฐ€ ์ค„์„ ์„œ ์žˆ์—ˆ๊ธฐ์— ํŒ€์žฅ์œผ๋กœ์„œ ์ด ์ •๋„ ์ฒ˜๋ฆฌ๋Š” ํ”„๋ก ํŠธ์—์„œ ํ•˜๊ฒ ๋‹ค ์ž์‹ ์žˆ๊ฒŒ ๋ง์„ ํ•˜๊ณ ๋Š” ํŽ˜์ด์ง€๋„ค์ด์…˜์— ๋Œ€ํ•œ ์ž๋ฃŒ๋ฅผ ์ด๊ฒƒ์ €๊ฒƒ ์ฐพ์•„๋ณด์•˜๋‹ค.

๐Ÿ’ก ํŽ˜์ด์ง€๋„ค์ด์…˜(Pagination)์ด๋ž€?
๋‹ค์ˆ˜์˜ ์ปจํ…์ธ ๋ฅผ ์—ฌ๋Ÿฌ๊ฐœ์˜ ํŽ˜์ด์ง€๋กœ ๋‚˜๋ˆ„๊ณ  ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ, ์ด์ „ & ๋‹ค์Œ ํŽ˜์ด์ง€ ๋ฒ„ํŠผ์œผ๋กœ ํŽ˜์ด์ง€๋ฅผ ์˜ค๊ฐˆ ์ˆ˜ ์žˆ๊ฒŒ ํ•˜๋Š” ๊ฒƒ.

๊ทธ๋ฆฌ๊ณ  ๋‹น์—ฐํžˆ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋นผ๋ฉด ์‹œ์ฒด์ธ JavaScript ๋‹ต๊ฒŒ ํŽ˜์ด์ง€๋„ค์ด์…˜์„ ์œ„ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋˜ํ•œ ์กด์žฌํ–ˆ๋‹ค.

 

react-paginate

A ReactJS component that creates a pagination.. Latest version: 8.2.0, last published: 6 months ago. Start using react-paginate in your project by running `npm i react-paginate`. There are 537 other projects in the npm registry using react-paginate.

www.npmjs.com

ํ•˜์ง€๋งŒ, ์›น ํ”„๋ก ํŠธ์—”๋“œ ๊ฐœ๋ฐœ์ž๊ฐ€ ๋˜๋ ค๋ฉด ์ด ์ •๋„๋Š” ๊ตฌํ˜„ํ•ด๋ด์•ผ ํ•˜์ง€ ์•Š์„๊นŒ... ํ•˜๋Š” ๋งˆ์Œ์— ์ง์ ‘ ๊ตฌํ˜„ํ•ด๋ณด๊ธฐ๋กœ ํ•˜์˜€๋‹ค.

 

๐Ÿ”ง ํŽ˜์ด์ง€๋„ค์ด์…˜์„ ์œ„ํ•œ ๊ธฐ๋ณธ ์ง€์‹.

ํŽ˜์ด์ง€๋„ค์ด์…˜์„ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•ด์„œ ๋‹ค๋ฐฉ๋ฉด์œผ๋กœ ์ž๋ฃŒ๋ฅผ ์ ‘ํ–ˆ๊ณ , ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์š”์†Œ๋“ค์ด ์žˆ์–ด์•ผ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Œ์„ ์•Œ๊ฒŒ ๋˜์—ˆ๋‹ค.

  • ํ‘œ์‹œํ•  ๋‚ด์šฉ์˜ ์ „์ฒด ๊ธธ์ด
  • ํŽ˜์ด์ง€๋งˆ๋‹ค ํ‘œ์‹œํ•  ๋‚ด์šฉ์˜ ํ•œ๋„
  • ๋‚ด์šฉ์„ ํ‘œ์‹œํ•  ํŽ˜์ด์ง€์˜ ์ „์ฒด ๊ฐœ์ˆ˜
  • ๊ฐ ํŽ˜์ด์ง€ ๋ณ„ ๊ฐ€์žฅ ์ฒ˜์Œ ํ‘œ์‹œ๋  ๋‚ด์šฉ์˜ ์ธ๋ฑ์Šค (์ด๋ฅผ offset์ด๋ผ๊ณ  ํ•˜๋Š” ๊ฒƒ ๊ฐ™๋‹ค)

ํ‘œ์‹œํ•  ๋‚ด์šฉ์˜ ์ „์ฒด ๊ธธ์ด๋ถ€ํ„ฐ ์„ค๋ช…์„ ํ•ด๋ณด์ž๋ฉด ๋‚˜์—๊ฒŒ๋Š” ๋žญํ‚น ๋ฆฌ์ŠคํŠธ์˜ ๊ธธ์ด๊ฐ€ ๋˜๊ฒ ๋‹ค. ์ด์–ด์„œ ๋‚ด์šฉ์„ ํ‘œ์‹œํ•  ํŽ˜์ด์ง€์˜ ์ „์ฒด ๊ฐœ์ˆ˜๋Š” ํ‘œ์‹œํ•  ๋‚ด์šฉ์˜ ์ „์ฒด ๊ธธ์ด๋ฅผ ํŽ˜์ด์ง€๋งˆ๋‹ค ํ‘œ์‹œํ•  ๋‚ด์šฉ์˜ ํ•œ๋„๋กœ ๋‚˜๋ˆ„์–ด ๋ฐ˜์˜ฌ๋ฆผ ํ•˜๋ฉด ๋œ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด 50๊ฐœ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ํ•œ ํŽ˜์ด์ง€ ๋‹น 30๊ฐœ์”ฉ ํ‘œ์‹œํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ๋งŒ๋“ค์–ด์•ผ ํ•  ์ „์ฒด ํŽ˜์ด์ง€์˜ ๊ฐœ์ˆ˜๋Š” 50 / 30 = 2 (๋ฐ˜์˜ฌ๋ฆผ)๊ฐ€ ๋œ๋‹ค.

 

๊ฐ ํŽ˜์ด์ง€๋ณ„๋กœ ๊ฐ€์žฅ ์ฒ˜์Œ ํ‘œ์‹œ๋  ๋‚ด์šฉ์˜ ์ธ๋ฑ์Šค, ์ฆ‰ offset์„ ๊ตฌํ•ด๋ณด์ž. ์œ„์˜ ์˜ˆ๋ฅผ ๊ทธ๋Œ€๋กœ ๊ฐ–๊ณ ์˜ค์ž๋ฉด 50๊ฐœ์˜ ๋ฐ์ดํ„ฐ๋ฅผ 2 ํŽ˜์ด์ง€์— ๋‚˜๋ˆ  30๊ฐœ์”ฉ ๋ณด์—ฌ์ค„ ๊ฒฝ์šฐ 1 ํŽ˜์ด์ง€์— 30๊ฐœ, 2 ํŽ˜์ด์ง€์— 20๊ฐœ์”ฉ ์ถœ๋ ฅ์ด ๋  ๊ฒƒ์ด๊ณ , ๊ฐ offset์€ 1 ํŽ˜์ด์ง€์—์„œ๋Š” ๋ฆฌ์ŠคํŠธ์—์„œ 0๋ฒˆ์งธ ์ธ๋ฑ์Šค์˜ ์›์†Œ๊ฐ€ ๋  ๊ฒƒ์ด๊ณ , 2 ํŽ˜์ด์ง€์—์„œ๋Š” 30๋ฒˆ์งธ ์›์†Œ๊ฐ€ ๋  ๊ฒƒ์ด๋‹ค. 

 

offset์„ ๊ตฌํ•˜๋Š” ๊ณต์‹์€ ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

๐Ÿ’ก (ํ˜„์žฌ ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ - 1) * ํŽ˜์ด์ง€๋งˆ๋‹ค ํ‘œ์‹œํ•  ๋‚ด์šฉ์˜ ํ•œ๋„

์œ„์˜ ์˜ˆ์ฒ˜๋Ÿผ ํ•œ ํŽ˜์ด์ง€ ๋‹น 30๊ฐœ์”ฉ ์ถœ๋ ฅํ•  ๊ฒฝ์šฐ์˜ 1 ํŽ˜์ด์ง€ offset์„ ๊ตฌํ•  ๋•Œ ๊ณต์‹์„ ์ ์šฉํ•˜๋ฉด (1 - 1) * 30์ด ๋˜์–ด 0์ด ๋œ๋‹ค.

2 ํŽ˜์ด์ง€์˜ offset์„ ๊ตฌํ•  ๋•Œ๋„ ์ž˜ ๋“ค์–ด๋งž๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

 

๐Ÿค” ๋‚˜์˜ ์†”๋ฃจ์…˜

๋‚˜์˜ ๋ชฉํ‘œ

ํ•œ ๋ฒˆ์— 5 ํŽ˜์ด์ง€๋ฅผ ์˜ค๊ฐˆ ์ˆ˜ ์žˆ๊ฒŒ ํ•˜๋ฉฐ, ๋ฐ์ดํ„ฐ์˜ ์–‘์ด ๋งŽ์•„ ๊ทธ ์ด์ƒ์œผ๋กœ ๋Š˜์–ด๋‚  ๊ฒฝ์šฐ ์ด์ „, ๋‹ค์Œ ํŽ˜์ด์ง€๋กœ ๋„˜์–ด๊ฐˆ ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ ๊ตฌํ˜„.

๋‹ค์Œ ํŽ˜์ด์ง€๋„ค์ด์…˜์œผ๋กœ ๋„˜์–ด๊ฐˆ ๋•Œ์—๋Š” 5 ํŽ˜์ด์ง€ ์ดํ›„์˜ 6ํŽ˜์ด์ง€๋ฅผ ๋ฐ”๋กœ ๋ณด์—ฌ์ค„ ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค. ์ด ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•ด ํŽ˜์ด์ง€๋„ค์ด์…˜์˜ ํŽ˜์ด์ง€๋„ค์ด์…˜์„ ๊ตฌํ˜„ํ•ด์•ผ ํ–ˆ๋‹ค. (์ค‘์ฒฉ ํŽ˜์ด์ง€๋„ค์ด์…˜ ใ„ทใ„ท)

 

ํŽ˜์ด์ง€๋„ค์ด์…˜์„ ์œ„ํ•œ Pagination ์ปดํฌ๋„ŒํŠธ

๋ฆฌ์ŠคํŠธ์˜ ํŽ˜์ด์ง€๋„ค์ด์…˜์„ ์œ„ํ•œ Pagination ์ปดํฌ๋„ŒํŠธ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํ•ญ๋ชฉ์„ props๋กœ ๋ฐ›์•„๋“ค์ธ๋‹ค.

  • listLen : number / ๋ฆฌ์ŠคํŠธ์˜ ์ „์ฒด ๊ธธ์ด
  • limit : number / ํ•œ ํŽ˜์ด์ง€์— ํ‘œ์‹œํ•  ๋ฐ์ดํ„ฐ ๊ฐœ์ˆ˜
  • curPage : number / ํ˜„์žฌ ๋ฆฌ์ŠคํŠธ์— ํ‘œ์‹œํ•  ํŽ˜์ด์ง€
  • setCurPage : any / curPage์˜ ๊ฐ’์„ ๋ณ€๊ฒฝํ•˜๊ธฐ ์œ„ํ•œ setState ํ•จ์ˆ˜

๊ทธ๋ฆฌ๊ณ  ์ด ์ปดํฌ๋„ŒํŠธ ์•ˆ์—์„œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ณ€์ˆ˜๋“ค์„ ์ถ”๊ฐ€๋กœ ์‚ฌ์šฉํ•˜์˜€๋‹ค. ๊ฐ ๋ณ€์ˆ˜์— ๋Œ€ํ•œ ์„ค๋ช…์€ ์ฃผ์„์œผ๋กœ ๋‹ฌ์•„๋‘์—ˆ๋‹ค.

const paginationLimit: number = 5; //ํŽ˜์ด์ง€๋„ค์ด์…˜ ๋‹น 5๊ฐœ์˜ ํ•ญ๋ชฉ์œผ๋กœ ์ œํ•œ 1 ~ 5, 6 ~ 10...
const numPages: number = Math.ceil(listLen / limit); //๋งŒ๋“ค์–ด์•ผ ํ•  ํŽ˜์ด์ง€์˜ ๊ฐฏ์ˆ˜
const [curPagination, setCurPaginaiton] = useState<number>(1); //ํ˜„์žฌ pagination์˜ index
const [paginationOffset, setPageinationOffset] = useState<number>(1); //pagination์˜ ์‹œ์ž‘ ์ง€์  (offset)
const [paginationArray, setPaginationArray] = useState<Array<number>>([]); //pagination์„ ์‚ฌ์šฉํ•  numPages๋งŒํผ์˜ ๋ฐฐ์—ด
const numPagination: number = Math.ceil(numPages / paginationLimit); //pagination์˜ pagination ๊ฐฏ์ˆ˜

์ด ์ค‘ curPagination, paginationOffset, numPagination์€ ์ด ํŽ˜์ด์ง€๋„ค์ด์…˜ ์ปดํฌ๋„ŒํŠธ ๋‚ด์—์„œ์˜ ํŽ˜์ด์ง€๋„ค์ด์…˜์„ ์œ„ํ•ด ์‚ฌ์šฉํ•œ ๊ฒƒ์ด๋‹ค.

1 ~ 5 ํŽ˜์ด์ง€๋ฅผ ํ™•์ธ ํ›„ ๋‹ค์Œ 6 ~ 10 ํŽ˜์ด์ง€๋ฅผ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด ๋‹ค์Œ์œผ๋กœ ๋„˜์–ด๊ฐˆ ๊ฒฝ์šฐ 6 ํŽ˜์ด์ง€๋ถ€ํ„ฐ ๋ฆฌ์ŠคํŠธ์— ๋ณด์—ฌ์ฃผ๊ธฐ ์œ„ํ•ด ํ•„์š”ํ–ˆ๋‹ค.

 

{paginationArray
        .slice(paginationOffset, paginationOffset + paginationLimit)
        .map((item, index) => (
          <Button key={index}>
            <p
              id={(item + 1).toString()}
              className={`page ${curPage === item + 1 ? "active" : ""}`}
              onClick={onClickHandler}
            >
              {item + 1}
            </p>
          </Button>
        ))}

์œ„ ์ฝ”๋“œ๋Š” ์ฃผ์š” ๋กœ์ง ์ฝ”๋“œ์ธ๋ฐ, Styled-Components๋ฅผ ์‚ฌ์šฉํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ์ด ์ ์€ ๊ฐ์•ˆํ•ด์ฃผ์‹œ๊ธธ....

paginationArray๋Š” ์ „์ฒด ํŽ˜์ด์ง€๋ฅผ ๋‚˜์—ดํ•˜์—ฌ ๋ฐฐ์—ด๋กœ ๋งŒ๋“  ๊ฒƒ์ด๋‹ค. ๊ฐ€๋ น ์ „์ฒด ๋ฆฌ์ŠคํŠธ์˜ ๊ธธ์ด๊ฐ€ 300๊ฐœ์—ฌ์„œ ์ „์ฒด ํŽ˜์ด์ง€์˜ ๊ฐœ์ˆ˜๊ฐ€ 10๊ฐœ๊ฐ€ ํ•„์š”ํ•˜๋‹ค๊ณ  ํ–ˆ์„ ๋•Œ, paginationArray๋Š” 0 ~ 9์˜ ๊ฐ’์ด ๋“ค์–ด์žˆ๋‹ค. ์ด๊ฒƒ์„ paginationOffset๋ถ€ํ„ฐ ์‹œ์ž‘ํ•˜์—ฌ paginationOffset + paginationLimit ๋งŒํผ slice() ํ•˜์—ฌ ํ•ด๋‹น ๋ถ€๋ถ„๋งŒ map()์„ ์ด์šฉํ•ด ๋ฆฌ์ŠคํŠธ ๋ Œ๋”๋ง์„ ์ง„ํ–‰ํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

๊ฐ€๋ น 1 ๋ฒˆ์งธ ํŽ˜์ด์ง€๋„ค์ด์…˜์„ ๋ณด์—ฌ์ค„ ๋•Œ์—๋Š” 0 ~ 4 ๊นŒ์ง€๋งŒ ์ž˜๋ผ ์ด๋ฅผ ๋ Œ๋”๋ง ํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

 

{curPagination >= 2 && (
      <PaginationButton id={"decrease"} onClick={onClickHandlerPagination}>
        <FontAwesomeIcon icon={faAngleLeft} size="2x" color="#1e98fd" />
      </PaginationButton>
)}
      
{curPagination != numPagination && (
      <PaginationButton id={"increase"} onClick={onClickHandlerPagination}>
        <FontAwesomeIcon icon={faAngleRight} size="2x" color="#1e98fd" />
      </PaginationButton>
)}

์ด ๋กœ์ง์€ ์ฒซ ํŽ˜์ด์ง€๋„ค์ด์…˜์„ ์ œ์™ธํ•œ ํŽ˜์ด์ง€๋„ค์ด์…˜์—์„œ ์ด์ „ ๋ฒ„ํŠผ์„ ๋ Œ๋”๋งํ•˜๊ณ , ๋งˆ์ง€๋ง‰ ํŽ˜์ด์ง€๋ฅผ ์ œ์™ธํ•œ ํŽ˜์ด์ง€๋„ค์ด์…˜์—์„œ ๋‹ค์Œ ๋ฒ„ํŠผ์„ ๋ Œ๋”๋ง ํ•˜๊ธฐ ์œ„ํ•œ ๋กœ์ง์ด๋‹ค. div์˜ id๋ฅผ ๊ฐ๊ฐ "decrease"์™€ "increase"๋กœ ์„ค์ •ํ•˜์—ฌ onClickHandlerPagination ์ด๋ฒคํŠธ ํ•ธ๋“ค๋ง์„ ํ†ตํ•ด ํ˜„์žฌ์˜ ํŽ˜์ด์ง€๋„ค์ด์…˜์„ ๋ณ€๊ฒฝํ•˜๊ฒŒ ๋œ๋‹ค.

 

์•„๋ž˜๋Š” Pagination ์ปดํฌ๋„ŒํŠธ์˜ ์ „์ฒด ์ฝ”๋“œ์ด๋‹ค.

  const onClickHandler = (e: React.MouseEvent) => {
    console.log((e.target as HTMLParagraphElement).id);
    setCurPage(Number((e.target as HTMLParagraphElement).id));
  };

  const onClickHandlerPagination = (e: React.MouseEvent) => {
  	//ํŽ˜์ด์ง€๋„ค์ด์…˜์˜ ์ด์ „, ๋‹ค์Œ์„ ์œ„ํ•œ onClick Handler
    const value: string = (e.target as any).id;
    console.log((e.target as any).id);

    if (value === "decrease") {
      setCurPaginaiton(curPagination - 1);
    } else if (value === "increase") {
      setCurPaginaiton(curPagination + 1);
      
    }
  };

  useEffect(() => {
  	//ํ˜„์žฌ ํŽ˜์ด์ง€๋„ค์ด์…˜์ด ๋ณ€๊ฒฝ๋˜๋ฉด ํŽ˜์ด์ง€๋„ค์ด์…˜ ์˜คํ”„์…‹๊ณผ ํ˜„์žฌ ํŽ˜์ด์ง€๋ฅผ ํ•ด๋‹น ํŽ˜์ด์ง€๋„ค์ด์…˜์˜ ์ฒซ ๋ฒˆ์งธ ํŽ˜์ด์ง€๋กœ ๊ฐฑ์‹ 
    setPageinationOffset((curPagination - 1) * paginationLimit);
    setCurPage(curPagination * paginationLimit - 4);
  }, [curPagination]);

  useEffect(() => {
  	//์ „์ฒด ํŽ˜์ด์ง€ ๊ฐœ์ˆ˜๋ฅผ ํ†ตํ•ด 0 ~ ์ „์ฒด ํŽ˜์ด์ง€ ๊ฐœ์ˆ˜๋ฅผ ๋‹ด์€ ๋ฐฐ์—ด์„ ์ƒ์„ฑํ•œ๋‹ค.
    let arr: Array<number> = Array(numPages)
      .fill()
      .map((item, index) => {
        return index;
      });
    setPaginationArray(arr);
  }, [numPages]);

  return (
    <PaginationContainer>
      {curPagination >= 2 && (
        <PaginationButton id={"decrease"} onClick={onClickHandlerPagination}>
          <FontAwesomeIcon icon={faAngleLeft} size="2x" color="#1e98fd" />
        </PaginationButton>
      )}
      {paginationArray
        .slice(paginationOffset, paginationOffset + paginationLimit)
        .map((item, index) => (
          <Button key={index}>
            <p
              id={(item + 1).toString()}
              className={`page ${curPage === item + 1 ? "active" : ""}`}
              onClick={onClickHandler}
            >
              {item + 1}
            </p>
          </Button>
        ))}
      {curPagination != numPagination && (
        <PaginationButton id={"increase"} onClick={onClickHandlerPagination}>
          <FontAwesomeIcon icon={faAngleRight} size="2x" color="#1e98fd" />
        </PaginationButton>
      )}
    </PaginationContainer>
  );
};

 

๋ฐ์ดํ„ฐ๋ฅผ ํ‘œ์‹œํ•  ListTable์—์„œ์˜ ํŽ˜์ด์ง€๋„ค์ด์…˜ ์†”๋ฃจ์…˜

๋žญํ‚น ๋ฆฌ์ŠคํŠธ๋Š” ์—ฌ๋Ÿฌ ๊ณณ์—์„œ ์“ฐ์ด๋ฏ€๋กœ ํ…Œ์ด๋ธ”์„ ๋ณ„๋„์˜ ์ปดํฌ๋„ŒํŠธ, ListTable๋กœ ์ถ”์ถœํ•˜์—ฌ ์žฌ์‚ฌ์šฉ์˜ ํŽธ์˜๋ฅผ ๋„๋ชจํ–ˆ๋‹ค. 

์ด ListTable ์ปดํฌ๋„ŒํŠธ์˜ props๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

  • head : Array<string> / ํ…Œ์ด๋ธ” ํ—ค๋“œ๋กœ ์“ฐ์ผ ๋ฌธ์ž์—ด ๋ฐฐ์—ด
  • list : React.ReactNode[][] / tr์— ํ‘œ์‹œํ•  ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ด์€ ๋ฆฌ์•กํŠธ ๋…ธ๋“œ ๋ฐฐ์—ด
  • offset : number / ๊ฐ ํŽ˜์ด์ง€์˜ ์‹œ์ž‘์ ์„ ์•Œ๋ ค์ฃผ๊ธฐ ์œ„ํ•œ offset
  • limit : number / ๊ฐ ํŽ˜์ด์ง€๊ฐ€ ๋ณด์—ฌ์ค„ ๋ฆฌ์ŠคํŠธ์˜ ์ตœ๋Œ€ ๊ธธ์ด
{data.slice(offset, offset + limit).map((row, index) => (
            <tr key={index}>
              {row.map((col, index) => (
                <td key={index}>{col}</td>
))}

์ „์ฒด ๋ฆฌ์ŠคํŠธ๋กœ ๋“ค์–ด์˜จ data๋ฅผ offset์—์„œ๋ถ€ํ„ฐ ์‹œ์ž‘ํ•˜์—ฌ offset + limit ๊นŒ์ง€ ์ž˜๋ผ map()์„ ํ†ตํ•ด ๋ฆฌ์ŠคํŠธ ๋ Œ๋”๋ง์„ ์ง„ํ–‰ํ•œ๋‹ค. ๋งŒ์•ฝ 1 ํŽ˜์ด์ง€์—ฌ์„œ offset์ด 0์ด๋ผ๋ฉด 0 ~ 30 ๊นŒ์ง€์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฆฌ์ŠคํŠธ์— ์ถœ๋ ฅ์‹œํ‚ค๊ฒŒ ๋˜๋Š” ๊ฒƒ์ด๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ํ•œ ํŽ˜์ด์ง€์— 30๊ฐœ์”ฉ ๋ฆฌ์ŠคํŠธ๋ฅผ ๋ณด์—ฌ์ค„ ์ˆ˜ ์žˆ๋‹ค.

 

์•„๋ž˜๋Š” ListTable ์ปดํฌ๋„ŒํŠธ์˜ ์ „์ฒด ์ฝ”๋“œ์ด๋‹ค.

const ListTable = ({ head, list, offset, limit }: Props) => {
  const [isMounted, setMounted] = useState(false);
  const [data, setData] = useState<React.ReactNode[][]>([]);

  useEffect(() => {
    setMounted(true);
  }, []); // Prevent hydration error

  useEffect(() => {
    setData(list);
  }, [list]);

  return (
    isMounted && (
      <TableStyle>
        <TheadStyle>
          {head.map((thData, index) => (
            <th key={index}>{thData}</th>
          ))}
        </TheadStyle>
        <TbodyStyle>
          {data.slice(offset, offset + limit).map((row, index) => (
            <tr key={index}>
              {row.map((col, index) => (
                <td key={index}>{col}</td>
              ))}
            </tr>
          ))}
        </TbodyStyle>
      </TableStyle>
    )
  );
};

 

์ „์ฒด ๋žญํ‚น์„ ๋ณด์—ฌ์ฃผ๋Š” RankingAll ์ปดํฌ๋„ŒํŠธ

RankingAll ์ปดํฌ๋„ŒํŠธ๋Š” ์œ„์˜ Pagination ์ปดํฌ๋„ŒํŠธ์™€ Pagination์„ ํ•ฉ์„ฑํ•ด์„œ ์‚ฌ์šฉ์ž๋ณ„ ์ „์ฒด ๋žญํ‚น์„ ๋ณด์—ฌ์ฃผ๋Š” ์ปดํฌ๋„ŒํŠธ๋‹ค.

์ด ์ปดํฌ๋„ŒํŠธ์—์„œ๋Š” axios๋ฅผ ํ™œ์šฉํ•œ ๋น„๋™๊ธฐ ํ†ต์‹ ์„ ํ†ตํ•ด API์—์„œ ์ „์ฒด ์‚ฌ์šฉ์ž ๋žญํ‚น์„ ๋ฐ›์•„์˜จ ๋’ค, ListTable์— ๋„˜๊ฒจ์ฃผ๊ธฐ ์œ„ํ•ด React.Node[][] ํƒ€์ž…์œผ๋กœ ๊ฐ€๊ณตํ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  curPage์™€ offset์„ ์ง€์ •ํ•˜์—ฌ ListTable๊ณผ Pagination์œผ๋กœ ๊ฐ๊ฐ props๋กœ ๋„˜๊ฒจ์ฃผ๊ฒŒ ๋œ๋‹ค.

 

๋‚ด๊ฐ€ ์ƒ๊ฐํ•˜๊ธฐ์— ํ˜„์žฌ ํŽ˜์ด์ง€์™€ ํ˜„์žฌ ํŽ˜์ด์ง€๋ฅผ ๊ฐฑ์‹ ํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ props๋กœ ๋‚ด๋ ค์ฃผ๋Š” ๊ฒƒ๋ณด๋‹ค ์ข‹์€ ๋ฐฉ๋ฒ•์ด ์žˆ์„ ๊ฒƒ ๊ฐ™์€๋ฐ ์ง€๊ธˆ์˜ ๋‚ด ๋จธ๋ฆฌ๋กœ์จ๋Š” ์—ฌ๊ธฐ๊ฐ€ ํ•œ๊ณ„์ธ ๊ฒƒ ๊ฐ™๋‹ค.

 

์„ค๊ณ„๋กœ๋Š” ๊ฐ ํ•ญ๋ชฉ๋ณ„ ๋žญํ‚น ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ๊ฐ์˜ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ Œ๋”๋ง ๋  ๋•Œ API๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ๋ฐ›์•„์˜ค๊ณ  ListTable์— ๋„˜๊ธฐ๊ณ ์ž ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ์ด๋Ÿฐ์‹์œผ๋กœ ๊ตฌํ˜„ํ•˜๊ฒŒ ๋˜์—ˆ๋‹ค. ์–ธ์ œ๋‚˜ ๊ทธ๋ ‡๋“ฏ ์ด๊ฒƒ๋ณด๋‹ค ์ข‹์€ ๋ฐฉ๋ฒ•์€ ๋” ์žˆ๊ฒ ์ง€๋งŒ...

 

RankingAll ์ปดํฌ๋„ŒํŠธ์˜ ์ „์ฒด ์ฝ”๋“œ

const RankingAll = () => {
  const limit: number = 30; //๋žญํ‚น ๋ชฉ๋ก ์ œํ•œ
  const [curPage, setCurPage] = useState<number>(1); //ํ˜„์žฌ ํŽ˜์ด์ง€
  const [offset, setOffset] = useState<number>(0);
  const [allListLen, setAllListLen] = useState<number>(0);
  const [rankingAll, setRankingAll] = useState<React.ReactNode[][]>([]);


  const refactorData = (list: userData[]) => {
    let tmpArray: React.ReactNode[][] = [];
	//๋ฆฌํŒฉํ† ๋ง ๋กœ์ง ์ƒ๋žต
    setRankingAll(tmpArray);
  };


  useEffect(() => {
    axios
      .get("http://Host:port/allRanking")
      .then(function (response) {
        // ์„ฑ๊ณต ํ•ธ๋“ค๋ง
        setAllListLen(response.data.length);
        refactorData(response.data);
        console.log("Loaded All Ranking Data");
      })
      .catch(function (error) {
        // ์—๋Ÿฌ ํ•ธ๋“ค๋ง
        console.log(error);
      })
      .finally(function () {
        // ํ•ญ์ƒ ์‹คํ–‰๋˜๋Š” ์˜์—ญ
      });
  }, []);

  useEffect(()=> {
    setOffset((curPage - 1) * limit);
    //์˜คํ”„์…‹ (ํŽ˜์ด์ง€ ์‹œ์ž‘์ ) ์ ์šฉ.
  },[curPage]);

  return (
    <ListAllContainer>
      <ListTable head={tableHead} list={rankingAll} offset={offset} limit={limit} />
      <Pagination listLen={allListLen} limit={limit} curPage={curPage} setCurPage={setCurPage}/>
    </ListAllContainer>
  );
};

 

๐Ÿ‘€ ๋งˆ์น˜๋ฉฐ.

์ „์ฒด ๋ฆฌ์ŠคํŠธ๊ฐ€ 50๊ฐœ ๋ฐ–์— ๋˜์ง€ ์•Š์•„ 2๊ฐœ์˜ ํŽ˜์ด์ง€๋งŒ ์กด์žฌํ•˜๋Š” ํŽ˜์ด์ง€๋„ค์ด์…˜.

props๋กœ ์ฃผ์–ด์ง€๋Š” listLen์„ ์ž„์˜๋กœ 1000์œผ๋กœ ๋Š˜๋ ธ์„ ๋•Œ์˜ ํŽ˜์ด์ง€๋„ค์ด์…˜.

 

๊ฒฐ๋ก ์ ์œผ๋กœ๋Š” ๋‚ด๊ฐ€ ์›ํ•˜๋Š” ๊ฒƒ์„ ๋ชจ๋‘ ๊ตฌํ˜„ํ•ด๋‚ด๊ธด ํ–ˆ๋‹ค.

์ฝ”๋“œ๊ฐ€ ์กฐ๊ธˆ์€ ์ง€์ €๋ถ„ํ•˜๊ณ  ์ด๊ฒƒ๋ณด๋‹ค ๋” ๋‚˜์€ ๋ฐฉ๋ฒ•์ด ์žˆ์„ ๊ฑฐ๋ผ ๋ถ„๋ช…ํžˆ ์ƒ๊ฐ์€ ํ•˜์ง€๋งŒ, ๊ทธ๋™์•ˆ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ์˜์กดํ•ด ์˜จ ๋‚ด๊ฐ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋Œ€์‹  ์Šค์Šค๋กœ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•ด ๋…ธ๋ ฅํ•˜๊ณ  ๊ณ ๋ฏผํ•œ ๊ณผ์ •์ด ๊ดœ์‹œ๋ฆฌ ์ž๋ž‘์Šค๋Ÿฝ๋‹ค.

 

์ฝ”์กธ์—… ์ž‘ํ’ˆ์„ ํ•™๊ธฐ ๋‚ด์— ๋๋‚ด์•ผ ํ•˜๋Š” ๋งŒํผ ์†๋„๋„ ์ค‘์š”ํ•˜๊ธฐ์— ์ด๋ฒˆ์˜ ํŽ˜์ด์ง€๋„ค์ด์…˜ ๊ตฌํ˜„์€ ์—ฌ๊ธฐ์„œ ๋๋งˆ์น ๊นŒ ํ•œ๋‹ค. ์กธ์ž‘์ด ๋๋‚˜๋ฉด ๊ทธ๋•Œ๋ผ๋„ ๋” ์ข‹์€ ๋ฐฉํ–ฅ์œผ๋กœ ๋ฆฌํŒฉํ† ๋ง์„ ํ•ด๋‚˜๊ฐ€๋ฉด ์ข‹์„ ๊ฒƒ ๊ฐ™๋‹ค.

 

๋‚ด๊ฐ€ ์ž๋ฃŒ๋ฅผ ํ•œ์ฐฝ ์ฐพ์•„๋ณผ ๋•Œ ๋ณธ ๋‹ค๋ฅธ ์‹ค๋ ฅ์ž๋ถ„๋“ค์˜ ๊ธ€์€ ์ด๊ฒƒ๋ณด๋‹ค ๋งŽ์ด ๊น”๋”ํ–ˆ๋˜ ๊ฒƒ ๊ฐ™์€๋ฐ ์–ด์งธ์„œ ๋‚ด๊ฐ€ ์“ด ๊ธ€์€ ๋ญ”๊ฐ€ ๋น™๋น™ ๋Œ์•„๊ฐ€๋Š” ๊ธฐ๋ถ„์ด๋‹ค. ๊ธ€๋„ ์ž์ฃผ ์จ๋ณด๋ฉด์„œ ๊ฐ์„ ์ตํ˜€์•ผ๊ฒ ๋‹ค.