unsplash API를 사용해서 갤러리 어플리케이션을 만들고 있다. 리액트의 useInfinteQuery를 사용하면 인피티티 스크롤을 쉽게 만들 수 있는데 문제는 unsplash API에서 응답 데이터에 총 페이지 개수는 주지만 현재 페이지나 다음 페이지가 있는지 없는지와 같은 페이지와 관련된 다른 데이터는 주지 않는다. 그래서 다음 페이지의 정보를 인피니티 스크롤로 받기 위해 따로 데이터를 넣어줘야 한다.
이미지 검색 기능을 쓰고 쓰고싶어서 처음에는 searchUrl 요청 api를 하나만 썼다. 그러나 이 api는 검색어가 없으면 이미지 데이터를 따로 주지 않아서 이 api로만 쓰면 메인페이지에 빈 페이지가 되었다.
처음에 들어갔을 때 핀터레스트 처럼 랜덤한 이미지가 띄워져 있었으면 좋을 것 같아서 랜덤한 이미지를 제공하는 api도 사용하기로 했다.
그러나 두 api가 주소도 다르고 받는 param도 달라서 컴포넌트를 따로 분리해야 될 까 싶었지만 유지보수 하기도 좋을 것 같고 코드 양도 줄일겸 if문으로 만약 key(검색어이다)가 있으면 serachUrl을 없으면 defaultUrl(렌덤이미지)로 요청을 하도록 했다.
key는 검색어로 유니크하기 때문에 react-query를 쓰는데는 문제가 없었다.
return 값으로 응답받은 이미지 데이터 말고도 몇가지를 설정해 줘야 했다.
const searchUrl = "https://api.unsplash.com/search/photos?";
const defaultUrl = "https://api.unsplash.com/photos/random?";
let url;
let params;
const fetchUrl = async (key , pageNum) => {
if(key.length > 0){
console.log(pageNum);
url = searchUrl;
params = {
query: key,
page: pageNum,
client_id: process.env.REACT_APP_UNSPLASH_KEY,
};
} else {
url = defaultUrl;
params = {
count: 10,
client_id: process.env.REACT_APP_UNSPLASH_KEY,
}
}
const response = await axios.get(url,{params});
if(key.length > 0){
return {...response.data, page: pageNum, isSearch: true};
} else {
return {
results: [...response.data],
page: pageNum,
isSearh: false,
}
}
}
const {data = {}, fetchNextPage, hasNextPage, isFetching, isLoading} = useInfiniteQuery(['page', searchTerm],
({queryKey , pageParam = 1}) => fetchUrl(queryKey[1], pageParam),
{
getNextPageParam: (lastPage) => {
if(lastPage.isSearch){
const {page, total_pages: totalPages} = lastPage;
return (page < totalPages) ? page + 1 : undefined;
} else {
const {page} = lastPage;
return page + 1;
}
}
})
위 코드에서 반환값에 현재 페이지가 몇 페이지인지 직접 넣어줬는데 이 값을 만약 unsplash API가 주는 데이터는 total_pages보다 작으면 page+1을 해주고 아니면 undefined를 반환하도록 했다
이렇게 하면 다음 페이지가 undefined인 경우 hasNextPage가 false가 되고 마지막 페이지 이후 요청이 안가도록 만들어 줄 수 있다.
undefined가 아닌경우 fetchNextPage에 다음 페이지의 요청 주소가 설정된다.
이 프로젝트의 경우 따로 인피니티 스크롤을 구현하지 않고 react-infinite-scroller를 사용했는데 hasMore과 loadMore을 prop으로 받는다.
<InfiniteScroll loadMore={fetchNextPage} hasMore={hasNextPage}>
<ImgContainer>
...
</ImgContainer>
</InfiniteScroll>