결과 화면

 


수정사항

https://jae-study.tistory.com/85

기존에는 react-js-pagination 패키지를 사용해 페이지네이션을 구현했다.

하지만 페이지네이션을 프론트에서 만들었을 경우, 서버와 데이터베이스의 부하가 발생할 수 있기 때문에 백앤드의 작업이 필요하다.

백앤드 없이 프론트에서 페이지네이션을 구현하고 싶다면 위의 링크를 참고한다.

 

https://jae-study.tistory.com/138

NestJs로 페이지네이션을 만들었다.

페이지네이션을 백앤드에서 만들어야 하는 이유에 대한 설명은 위의 링크를 참고한다.

 


1. boardReducer.tsx

  • src/store/boardReducer.tsx
  1. page 파라미터를 받는다. 타입스크립트이기 때문에 타입을 정의한다.
  2. axios.get을 사용해 page에 해당하는 데이터를 요청한다. URL은 쿼리 파라미터가 붙은 key=value 형태이다.
export const getBoardList = createAsyncThunk(
  'GET_BOARD_LIST',
  async (page: number) => {
    try {
      const response = await axios.get(`http://localhost:3001/board?page=${page}`)
      return response.data
    } catch (error) {
      console.log(error)
    }
  }
)

...

 

2. 페이지네이션에 해당하는 데이터 가져오기

  • src/pages/board/list/index.tsx
  1. dispatch를 사용해 page에 해당하는 게시판 데이터를 가져온다.
  2. axios를 통해 받아온 데이터가 객채(object) 형태이기 때문에 (배열처럼 보이지만 typeof로 확인하면 object이다.) [board, setBoard] state 변수를 만들고, 전개 연산자를 사용해 배열 형태로 바꾼다.
  3. axios를 통해 받아온 page 데이터가 문자(string) 형태이기 때문에 [page, setPage] state 변수를 만들고, Number로 타입을 변환한다.
  4. 페이지네이션 버튼에 대한 공통 함수(handlePagination)를 만든다.
import { useEffect, useState } from 'react'
import { useAppDispatch, useAppSelector } from '../../../hooks/useApp'
...

const BoardList = () => {
  // ** Hooks
  const dispatch = useAppDispatch()

  // ** Redux States
  const boardList = useAppSelector(state => state.boardReducer)

  // ** States
  const [board, setBoard] = useState<boardType[]>([])
  const [page, setPage] = useState<number>(1)

  // 페이지네이션
  function handlePagination(newPage: number) {
    if(newPage >= 1 && newPage <= boardList.meta.last_page) {
      dispatch(getBoardList(newPage))
    }
  }

  // 페이지가 로딩되면 게시판 리스트 가져옴
  useEffect(() => {
    dispatch(getBoardList(page))
  }, [])

  // 페이지가 로딩된 후 state 변수에 boardList 데이터 저장함
  useEffect(() => {
    if (boardList && boardList.data) {
      setBoard([...boardList.data])
      setPage(Number(boardList.meta.page))
    }
  }, [boardList])

  return (
    ...
  )
}

export default BoardList

 

3. 마크업 하기

  • src/pages/board/list/index.tsx.
  1. 삼항연산자를 사용해 데이터가 있고, 없을 때 마크업을 다르게 표현한다.
  2. map 메서드를 사용해 게시판 데이터를 보여준다.
  3. 처음으로, 이전, 다음, 마지막으로 버튼 기능을 구현한다.
const BoardList = () => {
  ...

  return (
    <div className="board-list">
      <Title children="Board list"/>

      <h4>Total post : {boardList.meta?.total}</h4>

      <table>
        <colgroup>
          <col width="15%"/>
          <col width="65%"/>
          <col width="20%"/>
        </colgroup>

        <thead>
          <tr>
            <th>No</th>
            <th>Title</th>
            <th>Date</th>
          </tr>
        </thead>

        <tbody>
          {
            board.length === 0 ? (
              <tr>
                <td colSpan={3}>데이터가 없습니다.</td>
              </tr>
            ) : (
              board.map((board, index) => {
                return (
                  <tr key={index}>
                    <td>{board.id}</td>
                    <td className="title">
                      <Link to={`/board/${board.id}`}>{board.title}</Link>
                    </td>
                    <td>{dayjs(board.created_at).format('YYYY.MM.DD')}</td>
                  </tr>
                )
              })
            )
          }
        </tbody>
      </table>

      {
        board.length === 0 ? (
          <></>
        ) : (
          <div className="pagination">
            {
              boardList.meta.last_page === 1 ? (
                <>
                  <button disabled>&#60;</button>
                  <p>{page}</p>
                  <button disabled>&#62;</button>
                </>
              ) : (
                <>
                  <button onClick={() => handlePagination(1)}>&#60;&#60;</button>
                  <button onClick={() => handlePagination(page - 1)}>&#60;</button>
                  <p>{page} / {boardList.meta.last_page}</p>
                  <button onClick={() => handlePagination(page + 1)}>&#62;</button>
                  <button onClick={() => handlePagination(boardList.meta.last_page)}>&#62;&#62;</button>
                </>
              )
            }
          </div>
        )
      }

      <Link to="/board/create">
        <Button children="Write" variant="primary"/>
      </Link>
    </div>
  )
}

export default BoardList

+ Recent posts