반응형
드디어.. 무한 스크롤을 완성했다. 사실 깔끔하게 짜진 못한 것 같은데 그래도 기능은 잘 동작하는 중이다!
무한 스크롤 구현에는 intersection-observer을 이용했다.
영화 정보는 한 번에 10개씩 받아오고 맨 아래로 내리면 추가적으로 10개씩 받아온다.
const [movieList, setMovieList, resetMovieList] = useRecoil(movieListState) // 영화 api로 받아온 영화 정보
const [currPage, setCurrPage] = useState<number>(1) // 현재 페이지 번호
const [isLoading, setIsLoading] = useState<boolean>(false) // 로딩 중 여부
const [totalResults, setTotalResults] = useState<number>(0) // 영화 총 갯수
const pageEnd = useRef(null)
먼저 state들을 정의해주고 useRef를 이용해서 마지막 요소를 observe할 수 있도록 한다.
로딩 상태일 때만 Loading이 보일 수 있게 하고 해당 요소에 ref를 붙여주면 된다.
return (
<div className={styles.search}>
<main className={styles.searchMain}>
{movieList.length ? (
<ul className={styles.itemList}>
{movieList.map((movie, idx) => {
const key = `movie-${idx}`
return <Item key={key} movie={movie} />
})}
<li className={styles.observeLi} ref={pageEnd}>
{isLoading && 'Loading... 😊'}
</li>
</ul>
) : (
<div>에러 메시지</div>
)}
</main>
</div>
)
useState안에서 intersection observer를 사용해주면 된다.
target의 isIntersecting이 true라면 (스크롤이 맨 아래 요소로 도달했으면) loadMore() 함수를 실행한다.
useEffect(() => {
let observer: IntersectionObserver
if (pageEnd.current) {
observer = new IntersectionObserver(
async (entries) => {
const target = entries[0]
if (target.isIntersecting) {
if (currPage * 10 < totalResults) { // 영화의 총 갯수보다 많이 호출되지 않도록 함.
loadMore()
}
}
},
{ threshold: 1.0 }
)
observer.observe(pageEnd.current)
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [totalResults])
loadMore()에서는 현재 페이지를 1씩 증가시켜주고, 현재 페이지가 변화할 때마다 loadMovies를 실행해 새로운 영화 데이터를 불러와준다.
// 현재 페이지가 변하면 다음 페이지의 영화를 불러옴.
useEffect(() => {
loadMovies(currPage)
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [currPage])
// 현재 페이지 +1
const loadMore = () => {
setCurrPage((prev) => prev + 1)
}
// 영화 정보 불러옴.
const loadMovies = async (page: number) => {
try {
const { data } = await getMovieListApi({
s: searchInputVal,
page,
})
if (page === 1) {
setTotalResults(data.totalResults)
}
if (data.Response === 'True') {
setMovieList((prev) => [...prev, ...data.Search])
}
} finally {
setIsSubmitted(false)
setIsLoading(true)
}
}
👀 전체 코드
어찌저찌 구현은 완료했지만 useEffect에서 함수 이름도 같이 넣어주면 요청이 계속 가는 경우가 생겨 어쩔 수 없이 그 줄에서만 eslint를 무시하는 옵션을 넣어주었다.
이틀동안 뭔가 될 것같은데 자꾸 오류가 나서 스트레스를 많이 받았는데 그래도 해결해서 다행이다 🥲
반응형
'Education > Wanted Pre-Onboarding FE Course' 카테고리의 다른 글
[TIL] 22.05.18 프리온보딩 Day 12 - React Query (0) | 2022.05.19 |
---|---|
[TIL] 22.05.17 프리온보딩 Day 11 (0) | 2022.05.18 |
[TIL] 22.05.11 프리온보딩 Day 7 (0) | 2022.05.12 |
[TIL] 22.05.10 프리온보딩 Day 6 - Recoil, CRA .env 설정 (0) | 2022.05.11 |
[TIL] 22.05.09 프리온보딩 Day 5 - TypeScript (0) | 2022.05.10 |