7/8 금
이번 프로젝트에서 무한 스크롤 적용을 맡게 되어 Intersection Observer 에 관하여 공부하게 되었다.
useIntersectionObserver.js - 훅으로 구현
const options = {
root: null,
rootMargin: "200px",
threshold: 0,
};
function useIntersectionObserver(ref, callback, dependencies = []) {
const onIntersection = ([entry], _observer) => {
if (entry.isIntersecting) {
callback();
}
};
React.useEffect(() => {
const observer = new IntersectionObserver(onIntersection, options);
if (ref.current) {
observer.observe(ref.current);
}
return () => observer.disconnect();
}, dependencies);
return [ref];
}
사용 - Main.jsx
function Main() {
const { movies, getMovies } = useMovieModel();
const [pageNo, setPageNo] = useState(1);
const endOfPageRef = useRef();
const [isDataLoaded, setIsDataLoaded] = useState(false);
const [hasReachedLastPage, setHasReachedLastPage] = useState(false);
useEffect(() => {
setIsDataLoaded(false);
getMovies(pageNo).then((response) => {
!response.data.results.length && setHasReachedLastPage(true);
setIsDataLoaded(true);
});
}, [pageNo]);
const [ref] = useIntersectionObserver(
endOfPageRef,
() => {
if (isDataLoaded) setPageNo(pageNo + 1);
},
[movies]
);
return (
<>
<Contents movies={movies} />
{hasReachedLastPage || movies.length < 20 ? <Footer /> : <EndOfPageDetector ref={ref} />}
</>
);
}
옵저버를 적용하면서 처음 직면했던 문제는 처음 데이터 로딩상태일때 이미 observe 대상인 페이지 끝단에 있을 detector 요소가 viewport 에 노출이 되어 callback 이 실행되 버리는 것이었다. 그래서 아직 영화 한 페이지가 로딩되기 전(movies.length < 20) 에는 나오지 않게 하는 조건을 추가하였다.
또한, 스크롤이 데이터의 끝에 도달한 경우 hasReachedLastPage 상태를 통해 detector 를 소멸하게 하였다.