● 이론1_ 페이지네이션(Pagenation) :
○ 일반적 페이지네이션 예시 상황 :
- 어떤 뉴스 웹페이지를 열 때, 모든 뉴스 데이터를 불러오는 것이 아닌, 일부분만 출력해주고,
- '더 보기' 버튼을 누를 때, || 커서를 내릴 때, => 그 동작 후에 몇개의 데이터를 불러온다.
○ 페이지 네이션 종류 : 2가지
- 종류1_ 오프셋 기반 페이지네이션 : 데이터 개수를 기반으로 한 페이지네이션
예) Request
Get https://example.com/posts?offset=20&limit=10
해석 :
- offset = 20 //현재 20개의 데이터 불러온 상태인데,
- limit=10 //동작 후에는 10개를 더 보내주는 예약어
- 서버로부터 받은 Response 내용
{
"padding" : {
"count" : 30,
"hasNext" : false
},
"posts" : [....]
}
- 오프셋 기반의 페이지 네이션 문제점
=> 데이터 구성이 자주 바뀌는 상황에서 사용할 때, 일부 데이터가 중복이나 생략이 될 수 있다. //블로그
- 종류2_ 커서 기반 페이지네이션 : 데이터를 가리키는 값 , 책갈피를 기반으로 한 페이지네이션
예) Request
Get https://example.com/posts?limit=10
해석 :
- limit=10 //동작 후에는 10개를 더 보내주는 예약어
- 서버로부터 받은 Response 내용
{
"padding" : {
"count" : 30,
//"hasNext" : false
"nextCursor" : "WerZxc"//다음 커서값을 넘겨준다.
},
"posts" : [....]
}
- 서버로부터 받은 Response 내용을 기반으로 다시 Request 내용 :
Get https://example.com/posts?cursor=WerZxc&limit=10
단점 : 오프셋기반 페이지내이션보다 만들기 까다롭다.
● 이론2_ 페이지네이션(Pagenation) 실습
○ 구현할 상황 :
- 처음에는 6개 데이터만 불러오고, '더보기' 버튼을 누를 시, 6개씩 더 데이터를 불러와 렌더링 하기
- 모든 데이터를 불러왔을 시, => '더 보기' 버튼을 비활성화 하기
○ 코드 순서 :
▶순서1_ 데이터 불러오는 Get 리퀘스트 메소드에 Argument와 , query 변수 에 limit, offset 반영하기 :
//Argument를 객체 형태, + offset =0 , limit = 6 으로 적용
//해석 : 초기에는 6개만 데이터 불러오도록 한다.
export async function getReviews({order='createdAt' , offset=0 , limit=6})
{
cosnt query = `order=${order}&offset=${offset}&limit=${limit}`;
//query 문자열에 limit , offset 반영
const response = await fetch(`https://learn.codeit.kr/api/film-reviews?${query}`);
const body = await response.json();
return body;
}
▶순서2_ App컴포넌트로 돌아가서, 데이터 인출 핸들러 메소드 + useEffect 메소드 수정 :
- 데이터 인출 핸들러 //handleLoad()
//데이터 인출 핸들러 , Argument를 orderQuery =>limit, offset 반영의 변수 'options'로 수정
const handleLoad = async (options)=>{
const {reviews} = await getReviews(options);
setItems(reviews);
}
- useEffect(콜백 , [검사용 내용물]);
const LIMIT = 6;//6개씩 불러오는 건 동작 중에 변화 없을 것이므로, const 상수로 저장
//useEffect의 콜백 함수 내의 handLoad()메소드 매개인자에 offset=0,limit=6 을 반영한 객체를 매개인자로 대입
useEffect(()=>{
handleLoad({order,offset : 0 , limit : LIMIT});
},[order]);
▶★순서3_ App컴포넌트에 '더보기'버튼 추가, 핸들러 적용 과정1 :
=> 동작에 따라 offset 값이 변화되므로, => useState 초기화
const [offset , setOffset] = useState(0);
=> handLoad에서 fetch된 Promise 객체의
- offset ==0 : 받은 데이터가 0개 =>그대로 Get https://example.com/posts?limit=10
- offset !=0 : 받은 데이터가 몇몇개 존재한 상태의 더 불러오기 요청 => Get https://example.com/posts?offset=현재출력되는데이터개수&limit=10
- 데이터 인출 핸들러 //handleLoad() 추가 적용 :
const handleLoad = async (options)=>{
const {reviews} = await getReviews(options);
//받은 reviews 객체의 offset에 따른 items배열 업데이트
if(reviews.offset==0)
{
setItems(reviews);
}
else{
setItems([...items],...reviews]);
//배열형태의 데이터를 안전하게 업데이트 하는 방법 => spread문법
}
//offset도 수정
setOffset(options.offset + reviews.length);
//기존 데이터 개수 + 더보기 동작으로 새로 추가된 데이터의 개수
}
▶순서4_ 데이터를 모두 불렀을 시, 더보기 버튼 비활성화 기능 적용 => hasNext의 값으로 구현
- 동작에 따라 hasNext 값이 변화되므로, => useState 초기화
const [offset , setOffset] = useState(0);
const [hasNext, setHasNext] = useState(false);
//초기값은 false
※참고로, hasNext는 모든 데이터가 불러올 시 ,false가 된다.
- '더보기' 버튼을 누를 시, 반환된 reviews데이터의 hasNext 값을 hasNext에 업데이트
const handleLoad = async (options) => {
const { reviews } = await getReviews(options);
if (options.offset === 0) {
setItems(reviews);
} else {
setItems([...items, ...reviews]);
}
setOffset(options.offset + options.limit);
setHasNext(reviews.hasNext);//업데이트
};
- 버튼 태그의 disabled 속성에 hasNext 가 false가될 시, 발현되도록 코드 작성 :
<button disabled={!hasNext} onClick={handleLoadMore}>
더 보기
</button>