무한 스크롤은 이미지나 컨텐츠의 길이 또는 갯수가 많을 때, 한번에 다 보여주지 않고 사용자가 마지막 컨텐츠를 볼 때 쯤 다음 컨텐츠가 있으면 불러오는 방식이다
Facebook, Instagram같이 게시물들을 한번에 보여주지 않고 사용자가 게시물을 보려고 계속해서 스크롤을 내릴 때, 마지막 불러온 데이터를 사용자가 볼 때 쯤, 다음 게시물을 불러온다.
구현 방식에는 크게 2가지가 있다.
window의 scroll 이벤트를 통해 스크롤의 위치를 이용해 스크롤의 위치가 마지막 컨텐츠의 끝에 다다를때 쯤 다음 컨텐츠를 불러오는 방식이다.
window.addEventListener("scroll", () => {
const isScrollEnded =
window.scrollY + window.innerHeight >= document.body.offsetHeight;
if (
isScrollEnded &&
!this.state.isLoading &&
this.state.totalCount > this.state.photos.length
) {
onScrollEnded();
}
});
window.scrollY : 문서가 수직으로 얼마나 스크롤됐는지 픽셀 단위로 반환
window.innerHeight : 브라우저의 UI 인터페이스를 뺀 DOM이 그려지는 화면의 크기를 말한다. (뒤로가기 UI or 북마크 밑으로 이루어진 화면, 세로 스크롤의 범위로 볼 수 있다.)
HTML.Element.offsetHeight : 세로 패딩과 테두리를 포함한 요소의 높이
window 이벤트 중 scroll 이벤트를 통해 구현한다.
지정한 DOM 객체를 계속해서 감시해 지정한 DOM 객체가 화면상에 들어오면 다음 데이터를 불러오는 방식이다.
const observer = new IntersectionObserver(
// entries는 observer할 대상
(entries) => {
// forEach를 통해 entries를 조회 map 사용 X
entries.forEach((entry) => {
const { photos, isLoading, totalCount } = this.state;
// 사진이 로딩중일 때, scroll 이벤트가 막 일어나면 계속해서 api 호출하는 버그가 발생할 수 있다.
// totalCount를 안 넣어주면 api 마지막 사진 li에서 obeserve 이벤트가 계속 발생하는 버그가 생긴다.
// entry가 화면에 나왔는지 확인하는 isIntersecting을 통해 알수 있다. (boolean)
if (entry.isIntersecting && !isLoading && photos.length < totalCount) {
console.log("entry 화면 끝", entry);
observer.unobserve(entry.target);
onScrollEnded();
}
});
},
{
//이건 기본 값, 감시할 요소를 제한시킬 때 사용하는 값
root: null,
//마진을 줘서 해당 마진만큼 여유를 줘서 감시
rootMargin: "40px",
// 중요한 값, 얼마만큼 보였는지 조절하는 값
threshold: 0.5,
}
);
//$last는 observer할 대상
const $last = $photo.querySelector("li:last-child");
if ($last) {
// observe를 통해 감시한다.
observer.observe($last);
}
};
프로그래머스 데브코스
MDN