결과 화면
수정사항
https://jae-study.tistory.com/85
기존에는 react-js-pagination 패키지를 사용해 페이지네이션을 구현했다.
하지만 페이지네이션을 프론트에서 만들었을 경우, 서버와 데이터베이스의 부하가 발생할 수 있기 때문에 백앤드의 작업이 필요하다.
백앤드 없이 프론트에서 페이지네이션을 구현하고 싶다면 위의 링크를 참고한다.
https://jae-study.tistory.com/138
NestJs로 페이지네이션을 만들었다.
페이지네이션을 백앤드에서 만들어야 하는 이유에 대한 설명은 위의 링크를 참고한다.
1. boardReducer.tsx
- src/store/boardReducer.tsx
- page 파라미터를 받는다. 타입스크립트이기 때문에 타입을 정의한다.
- 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
- dispatch를 사용해 page에 해당하는 게시판 데이터를 가져온다.
- axios를 통해 받아온 데이터가 객채(object) 형태이기 때문에 (배열처럼 보이지만 typeof로 확인하면 object이다.) [board, setBoard] state 변수를 만들고, 전개 연산자를 사용해 배열 형태로 바꾼다.
- axios를 통해 받아온 page 데이터가 문자(string) 형태이기 때문에 [page, setPage] state 변수를 만들고, Number로 타입을 변환한다.
- 페이지네이션 버튼에 대한 공통 함수(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.
- 삼항연산자를 사용해 데이터가 있고, 없을 때 마크업을 다르게 표현한다.
- map 메서드를 사용해 게시판 데이터를 보여준다.
- 처음으로, 이전, 다음, 마지막으로 버튼 기능을 구현한다.
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><</button>
<p>{page}</p>
<button disabled>></button>
</>
) : (
<>
<button onClick={() => handlePagination(1)}><<</button>
<button onClick={() => handlePagination(page - 1)}><</button>
<p>{page} / {boardList.meta.last_page}</p>
<button onClick={() => handlePagination(page + 1)}>></button>
<button onClick={() => handlePagination(boardList.meta.last_page)}>>></button>
</>
)
}
</div>
)
}
<Link to="/board/create">
<Button children="Write" variant="primary"/>
</Link>
</div>
)
}
export default BoardList