토이 프로젝트 중 React + Spring 조합으로 개발하는 과정에서 Pagination이 필요해서 구현하다가
직접 만든 거 말고 기존에 있는 라이브러리를 사용해 보는 건 어떨까🤔 라는 생각이 들어서 찾아보게 되었다.
그렇게 react-js-pagination라는 라이브러리를 활용하여 Pagination을 구현하였고 관련 내용을 공유하고자 한다.
🐕 0. 준비
React 프로젝트 Terminal에 하기 명령을 입력하여 react-js-pagination 라이브러리를 받는다.
npm i react-js-pagination
🐕 1. Spring 서버 페이징 처리
Controller
@GetMapping("/api/study")
public ResponseEntity<Pagination> getPublicStudyList(@PageableDefault Pageable pageable) {
log.debug("[getPublicStudyList] call ");
Pagination<List<StudyDto>> response = studyService.getPublicStudyList(pageable);
return new ResponseEntity<>(response, HttpStatus.OK);
}
1. 컨트롤러에 Pageable 파라미터를 받는다.
Pageable를 파라미터로 받게 되면 클라이언트에서 조회에 필요한 만큼을 쿼리 파라미터로 요청할 수 있게 된다.
( size = 목록 개수, page = 페이지 번호, sort = 정렬 기준 )
@PageableDefault 어노테이션이 있으면, 기본으로 page = 0, size=10가 설정된다.
Service
@Transactional(readOnly = true)
public Pagination<List<StudyDto>> getPublicStudyList(Pageable pageable) {
Page<Study> studyPage = studyRepository.findAllBySecretAndIsUse(false, IsUse.Y, pageable);
List<StudyDto> data = studyPage.getContent().stream()
.map(StudyDto::entityToDto)
.collect(Collectors.toList());
return new Pagination<>(studyPage, data);
}
Repository
Page<Study> findAllBySecretAndIsUse(Boolean secret, IsUse isUse, Pageable pageable);
2. Repository로 Pageable을 전달하여 페이징 처리된 개수만큼의 데이터를 가져온다.
JpaRepository가 상속된 Repository에서 메서드 파라미터로 Pageable을 전달하면 자동으로 페이징 처리를 해준다.
이때 반드시 반환 타입을 Page <Entity>로 해야 한다.
Dto
@Getter
@ToString
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public final class Pagination<T> {
private PageInfo page;
private T data;
public Pagination(Page page, T data) {
this.page = new PageInfo(page);
this.data = data;
}
@Getter
@ToString
@NoArgsConstructor(access = AccessLevel.PRIVATE)
private static final class PageInfo {
private long totalElements;
private int totalPages;
private int size;
private int number;
private boolean first;
private boolean last;
public PageInfo(Page page) {
this.totalElements = page.getTotalElements();
this.totalPages = page.getTotalPages();
this.size = page.getSize();
this.number = page.getNumber();
this.first = page.isFirst();
this.last = page.isLast();
}
}
}
3. Dto로 페이징 정보와 결과 값을 담아서 전달한다.
DB로부터 가지고 온 결과 Page에는 페이징에 필요한 많은 정보들을 담고 있다.
이를 바탕으로 구현에 필요한 정보들을 Dto에 담아서 반환한다.
필드 명 | 설명 |
totalElements | 전체 필드 수 |
totalPages | totalElements / size |
size | 페이지 당 조회 수 |
number | 현재 페이지 번호 (0부터 시작) |
first | 첫 번째 여부 |
last | 마지막 여부 |
🐕 2. React
Api
export const fetchPublicStudyList = ({ page, size, sort }) =>
client.get(`/api/study?page=${page}&size=${size}&sort=${sort}`);
page, size, sort를 설정해서 서버에 요청하면 Pagination과 동일한 형태의 값을 받아오게 된다.
SCSS
.pagination {
display: flex;
align-items: center;
justify-content: center;
}
ul {
list-style: none;
padding: 0;
}
ul.pagination li {
display: inline-block;
width: 40px;
height: 40px;
display: flex;
justify-content: center;
align-items: center;
font-size: 1rem;
}
ul.pagination li:first-child {
}
ul.pagination li:last-child {
}
ul.pagination li a {
text-decoration: none;
color: #22b8cf;
font-size: 1rem;
}
ul.pagination li.active a {
color: white;
}
ul.pagination li.active {
border-radius: 40px;
background-color: #22b8cf;
}
ul.pagination li a:hover,
ul.pagination li a.active {
}
.page-selection {
}
Component
<Pagination
activePage={page.number + 1}
itemsCountPerPage={10}
totalItemsCount={page.totalElements}
pageRangeDisplayed={5}
firstPageText={
<KeyboardDoubleArrowLeft
style={{ fontSize: 25, display: 'flex', color: '#22b8cf' }}
/>
}
prevPageText={
<ArrowBackIos
style={{ fontSize: 15, display: 'flex', color: '#22b8cf' }}
/>
}
nextPageText={
<ArrowForwardIos
style={{ fontSize: 15, display: 'flex', color: '#22b8cf' }}
/>
}
lastPageText={
<KeyboardDoubleArrowRight
style={{ fontSize: 25, display: 'flex', color: '#22b8cf' }}
/>
}
onChange={(e) => getPublicStudyList(e - 1)}
/>
서버에서 가지고 온 페이징 정보를 바탕으로 속성 값들을 설정한다.
라이브러리는 다양한 속성을 가지고 있지만, 그중 사용했던 속성에 대해서만 설명하자면 다음과 같다.
(전체 속성에 대한 설명은 하단의 REFERENCE를 참고 바람)
속성 명 | 설명 |
activePage
|
활성화 된 페이지 (Pagination = number) |
itemsCountPerPage
|
페이지당 화면에 보여줄 리스트 수 (Pagination = size) |
totalItemsCount
|
전체 개수 (Pagination = totalElements) |
pageRangeDisplayed
|
보여줄 페이지 범위 (5를 설정하면 1~5 버튼이 보인다) |
firstPageText
|
가장 이전 페이지로 가는 Text (String, React Element 타입 지원) |
prevPageText
|
이전 페이지로 가는 Text (String, React Element 타입 지원) |
nextPageText
|
다음 페이지로 가는 Text (String, React Element 타입 지원) |
lastPageText
|
가장 마지막 페이지로 가는 Text (String, React Element 타입 지원) |
onChange
|
페이지가 바뀔 때 이벤트 (e는 현재 페이지 번호를 가지고 있다.) |
PageText 속성은 React Element도 지원하기 때문에, Material Icon의 UI를 사용하면 더 예쁘게 꾸밀 수 있다.
한 번 scss + Material Icon를 활용해서 각 프로젝트에 맞는 개성 있는 페이징을 구현해 보자! 👍
REFERENCE
https://www.npmjs.com/package/react-js-pagination
https://mui.com/material-ui/material-icons/
https://github.com/wwwaiser/react-js-pagination
'React' 카테고리의 다른 글
[React] router v6에서 JWT 인증과 Private 컴포넌트를 통한 화면 접근 보안 구현하기 (0) | 2023.02.25 |
---|---|
JavaScript Date 타입을 Java LocalDateTime으로 전달하기 (0) | 2023.02.01 |
Proxy 설정을 통해 로컬에서 개발중인 React와 서버 통신 설정하기 (0) | 2023.01.08 |
댓글