💬 문제
react-admin의 Data Previder부분을 보면 아래와 같은 방식으로 데이터를 가져올 때 페이지 네이션 기능이 적용이 된다고 생각하고 코드를 작성했었다.
//dataProvider
getList: (resource, params) => {
const { page, perPage } = params.pagination;
const { field, order } = params.sort;
const query = {
sort: JSON.stringify([field, order]),
range: JSON.stringify([(page - 1) * perPage, page * perPage - 1]),
filter: JSON.stringify(params.filter),
};
const url = `${apiUrl}/${resource}?${stringify(query)}`;
** return httpClient(url).then(({ headers, json }) => ({
data: json,
total: parseInt(headers.get('content-range').split('/').pop(), 10),
}));
},
맨 아래줄의 total
부분에서 나는 이전 포스팅 에서 X-Total-Count
로 데이터 길이를 가저오고 있었기 때문에 이 부분만 아래와 같이 수정을 해주었다.
total: parseInt(headers.get("X-Total-Count").split("/").pop(), 10),
이렇게 하면 전체 리스트를 가저오는 페이지에서 페이지 네이션 기능이 잘 적용이 된 거 처럼 보인다.
하지만 NEXT를 누르거나 페이지 번호를 이동해도 화면에 아무런 변화가 일어나지 않는 문제를 발견했다.
🤔 원인
getList
로 전체 리스트를 받아올 때 어떤 식으로 서버에 요청이 가고 있는지 확인을 해봤다.
/userlist?filter=%7B%7D&range=%5B0%2C9%5D&sort=%5B%22id%22%2C%22ASC%22%5D
req.url
을 확인해보면 위에처럼 요청을 보내고 있는 걸 확인할 수 있었다.
이 url
을 이용하면 될 거 같다는 생각이 들어서 DataProvider에서 url을 정의하는 부분을 내가 필요한 내용들로 알기쉽게 수정해 보기로 했다.
🔗참고링크
//dataProvider
getList: (resource, params) => {
const { page, perPage } = params.pagination;
const { field, order } = params.sort;
const { q } = params.filter;
console.log(":::::page::::", page);
console.log(":::::q:::::", q);
console.log("::::perPage:::::", perPage);
// Pagination and sort
const query = `limit=${perPage}&page=${page}&orderBy=${field}&orderDir=${order}&search=${q}`;
// Filter?
console.log("::::query:::::", query);
const url = `${apiUrl}/${resource}?${query}`;
console.log(":::::url::::", url);
return httpClient(url).then(({ headers, json }) => ({
data: json,
total: parseInt(headers.get("X-Total-Count").split("/").pop(), 10),
}));
},
getList
를 이렇게 수정하고 다시 서버 쪽 요청을 확인해 봤다.
/admin/beerlist?limit=10&page=1&orderBy=id&orderDir=ASC&search=undefined
이 요청에 담긴 req.url
에서 limit
과 page
를 활용하면 페이지 네이션을 사요할 수 있게다는 생각이 들었다.
💡 해결
/admin/beerlist?limit=10&page=1&orderBy=id&orderDir=ASC&search=undefined
/admin/beerlist?limit=10&page=2&orderBy=id&orderDir=ASC&search=undefined
/admin/beerlist?limit=10&page=3&orderBy=id&orderDir=ASC&search=undefined
페이지를 이동할 때마다 url 쿼리에서 page부분이 변하는걸 확인할 수 있었다.
limit
과 page
를 추출한다.⇒ limit=10
page=2
일때 id가 11 ~ 20까지의 리스트를 보내준다. 이걸 식으로 작성해보면
( limit x page ) - limit
~~ ( limit x page )
안의 범위를 구한다.limit
과 page
를 추출할 방법으로 처음에는 slice나 split를 생각했지만 limit
의 자리수가 변하거나 하는 등의 변수가 발생할 수 있기 때문에 정규식을 이용해 보기 로했다.
const url = '/userlist?limit=10&page=1&orderBy=id&orderDir=ASC';
const getLimit = /limit=(\d+(\d)*)/;
const getPage = /page=(\d+(\d)*)/;
const limit = url.match(getLimit);
const page = url.match(getPage);
위와 같은 방법으로 limit과 page 다음의 숫자를 가져올 수 있었다. 하나씩 뜯어보면,
\d
: 숫자 하나와 매칭
⇒ limit=10
에서 limit 뒤의 1
을 가져온다.
(\d)*
: 다음의 숫자가 있을 수도 있고 없을 수도 있는 경우
⇒ limit=10
에서 1
다음에 숫자가 있기 때문에 0
도 가져와서 10
이된다.
위의 내용들을 모두 코드로 적용해보았다.
// server/admin
const { url } = req;
const limitArr = url.match(/limit=(\d+(\d)*)/);
const pageArr = url.match(/page=(\d+(\d)*)/);
if (limitArr && pageArr) {
const limit = Number(limitArr[1]);
const page = Number(pageArr[1]);
// string 배열로 나오기 때문에
const start = limit * page - limit + 1;
const end = limit * page;
const sendBeerList = await Beer.findAll({
raw: true,
where: {
id: {
[Sequelize.Op.between]: [start, end],
},
},
order: [[target, sort]],
});
}
//생략..
이렇게하면 url 쿼리 요청으로 limit과 page에 맞는 범위의 데이터를 보낼 수 있었고 페이지 네이션 기능도 제대로 잘 작동하는 걸 확인할 수 있었다.
와 사이트 잘만드셨네요!!