● 이론0_ 데이터의 offset , limit , hasNext 속성 정의
○ 데이터의 필드 구성 중 :
- offset : 현재 fetch 된 데이터의 수
- limit : 다음 fetch할 데이터의 수
- hasNext :
- Api에 fetch할 데이터 수가 남아있다 => true
- Api에 fetch할 데이터수가 남아있지 않다 => false
● 이론1_ offset 기반 페이지네이션 구현 코드 작성하기
○ 순서1_ Get 메소드의 query에 offset , limit 반영하기
- Api.js
//매개인자를 객체로 수정
export async function getReviews({
order = "createdAt",
offset = 0,
limit = 6,
}) {
const query = `order=${order}&offset=${offset}&limit=${limit}`;
const response = await fetch(
`https://learn.codeit.kr/api/film-reviews?${query}`
);
const body = await response.json();
}
○ 순서2_ Get 메소드와 관련된 메소드 수정
- App.js
- handLoad 메소드
- useEffect 메소드
1_ handLoad()
const loadReviews = async (options) => {
const { reviews } = await getReviews(options);
setItems(reviews);
};
2_ useEffect()
const LIMIT = 6;//불러올 데이터의 숫자는 변하지 않는다.
...
const loadReviews = async (options) => {
const { reviews } = await getReviews(options);
setItems(reviews);
};
//useEffect 부분
useEffect(() => {
loadReviews({ order, offset, limit: LIMIT });
//상수형태로 limit는 고정
}, [order]);
○ 순서3_ "더불러오기" 기능을 하면, 동작을 수행하면서, offset값은 변한다.
=> useState로 offset 값 등록
const [offset, setOffset] = useState(0);
//초기 offset값 0으로 초기화
○ 순서4_ "더불러오기" 버튼의 핸들러 등록
=> hadleLoad메소드 수정, handleMoreLoadClick 핸들러 구현
- handleLoad 수정
const handleLoad = async (options) => {
//offset : fetch의 결과물
const {reviews} = await getReviews(options);
if(options.offset==0)
{
setItems(reviews);
}
else
{
//spread 문법으로, 기존 items의 베열에 review를 추가적용
setItems([...items,...reviews]);
}
//offset과 hasNext 업데이트 부분
setOffset(items.length);
}
- handleMoreLoadClick 핸들러
const handleMoreLoad = () => {
handLoad({order, offset , limit : LIMIT});
}
○ 순서5_ 버튼 태그 추가 + 핸들러 적용
return (
<div>
<div>
<button onClick={handleNewestClick}>최신순</button>
<button onClick={handleBestClick}>베스트순</button>
</div>
<ReviewList items={sortedItems} onDelete={handleDelete} />
<button disabled={!hasNext} onClick={handleLoadMore}>
더 보기
</button>
</div>
);
=> 여기까지 결과물 :
- App.js :
import { useState, useEffect } from "react"; //useEffect 추가하기기
import ReviewList from "./ReviewList";
import { getReviews } from "../api";
const LIMIT = 6;
function App() {
const [items, setItems] = useState([]);
const [order, setOrder] = useState("createdAt");
const [offset, setOffset] = useState(0);
//Get 메소드 있는 부분 모두 수정 :
//loadReviews
const loadReviews = async (options) => {
const { reviews } = await getReviews(options);
if (options.offset === 0) {
setItems(reviews);
} else {
setItems([...items, ...reviews]);
}
setOffset(options.offset + items.length);
};
//useEffect 부분
useEffect(() => {
loadReviews({ order, offset, limit: LIMIT });
}, [order]);
const sortReviews = items.sort((a, b) => {
return b[order] - a[order];
});
const handleRatingSort = () => {
setOrder("rating");
};
const handleCreatedAtSort = () => {
setOrder("createdAt");
};
const handleMoreLoad = async () => {
await loadReviews({ order, offset, limit: LIMIT });
};
const handleDeleteReview = (id) => {
const deleteAfterReviews = items.filter((item) => id !== item.id);
setItems(deleteAfterReviews);
};
return (
<div>
<div>
<button onClick={handleCreatedAtSort}>최신순</button>
<button onClick={handleRatingSort}>베스트순</button>
</div>
<ReviewList items={sortReviews} onDelete={handleDeleteReview} />
<div>
<button onClick={handleMoreLoad}>더보기</button>
</div>
</div>
);
}
export default App;
- api.js
//매개인자에 order 추가
export async function getReviews({
order = "createdAt",
offset = 0,
limit = 6,
}) {
const query = `order=${order}&offset=${offset}&limit=${limit}`;
//Get메소드에 query문자열 따로 추가
const response = await fetch(
`https://learn.codeit.kr/api/film-reviews?${query}`
);
//fetch의 url에 query작용
const body = await response.json();
return body;
}
○ 순서6_ hasNext를 이용해, 데이터를 모두 불러왔을 시(hasNext==false), 버튼 비활성화 시키기
①. hasNext를 useState 등록
②. handleLoad에서, fetch의 반환값에 따로 paging을 추가, setHasNext에 paging의 hasNext를 업데이트
③. button 태그의 disable 속성을 이용해 , hasNext가 false일 시, 비활성화 구현
const [hasNext , setHasNext] = useState(false);
const handleLoad = async (options)=>{
const {reviews , paging} = await getReviews(options);
//paging 객체의 프로퍼티 추가
if(options.offset===0)
{
setItems(reviews);
}
else
{
setItems([...items, ...options]);
}
setOffset(items.length);
setHasNext(paging.hasNext);
//paging의 hasNext로 업데이트
}
<button disable={!hasNext} onClick={handleMoreLoad}>더 보기</button>
=> 여기까지 결과물 :
import { useState, useEffect } from "react"; //useEffect 추가하기기
import ReviewList from "./ReviewList";
import { getReviews } from "../api";
const LIMIT = 6;
function App() {
const [items, setItems] = useState([]);
const [order, setOrder] = useState("createdAt");
const [offset, setOffset] = useState(0);
const [hasNext, setHasNext] = useState(false);
const loadReviews = async (options) => {
const { reviews, paging } = await getReviews(options);
if (options.offset === 0) {
setItems(reviews);
} else {
setItems([...items, ...reviews]);
}
setOffset(options.offset + items.length);
setHasNext(paging.hasNext);
};
//useEffect 부분
useEffect(() => {
loadReviews({ order, offset, limit: LIMIT });
}, [order]);
const sortReviews = items.sort((a, b) => {
return b[order] - a[order];
});
const handleRatingSort = () => {
setOrder("rating");
};
const handleCreatedAtSort = () => {
setOrder("createdAt");
};
const handleMoreLoad = async () => {
await loadReviews({ order, offset, limit: LIMIT });
};
const handleDeleteReview = (id) => {
const deleteAfterReviews = items.filter((item) => id !== item.id);
setItems(deleteAfterReviews);
};
return (
<div>
<div>
<button onClick={handleCreatedAtSort}>최신순</button>
<button onClick={handleRatingSort}>베스트순</button>
</div>
<ReviewList items={sortReviews} onDelete={handleDeleteReview} />
<div>
<button disabled={!hasNext} onClick={handleMoreLoad}>
더보기
</button>
</div>
</div>
);
}
export default App;