window의 scroll이벤트를 통해 스크롤링이 일어날 때마다 화면 전체의 높이와 스크롤 위치를 통해 스크롤이 컨텐츠 끝 즘에 다다랐는지 체크해서 처리하는 방식
this.state = {
limit: 5,
nextStart: 0,
photos: [],
totalCount: 0,
isLoading: false,
};
fetchPhotos()의 내부 과정과 발생 시점
this.setState({
...this.state,
nextStart: nextStart + limit, // nextStart가 0으로 시작해서 limit만큼 계속 더해짐 시작점이 0,5,10,15,20...로 증가
photos: [...this.state.photos, ...photos], // 이미 불러와진, 전 상태에 새로 받은 데이터를 누적해서 상태를 변경해줌
// photos: this.state.photos.concat(photos), // 두 배열 요소들을 합친 새로운 배열을 반환함
isLoading: false, // 로딩 중을 해제해 줌
});
onScrollEnded: () => {
fetchPhotos(); // 이벤트가 실행될 때 불러짐
},
누적된 데이터로 화면을 렌더링 할 경우 데이터가 바뀔때마다 전부 새롭게 렌더링 되어 화면 위로 올라가게 된다.
photos.forEach((photo) => {
//있는 거는 거르고 새로운 것만 렌더링
// 데이터를 돌면서 photo의 id 기준으로 렌더링이 되어있는지 체크 (data-id사용)
// 현재 ul의 li중 데이터에 포함된 id가 데이터 속성이 아니라면 새로 생성한다
// 이 id로 만들어진 li가 있냐? 없으면 만들어
if ($photos.querySelector(`li[data-id="${photo.id}"]`) === null) {
// 없으면 li생성하고 $photos에 appendChild
const $li = document.createElement('li');
$li.setAttribute('data-id', photo.id);
$li.style = 'list-style:none;';
$li.innerHTML = `<img width="100%" src="${photo.imagePath}"/>`;
$photos.appendChild($li);
}
});
1.스크롤이 끝났고
2.데이터를 불러오는 중이 아니고
3.전테 데이터가 다 불러지기 전이라면
const isScrollEnded =
window.innerHeight + window.scrollY + 100 >= document.body.offsetHeight;
// 1.브라우저의 내부 높이 + 문서가 수직으로 얼마나 스크롤됐는 지 픽셀 단위로 반환된 값 - 스크롤된 전체 브라우저 높이
// 2.body컨텐츠 높이
// body보다(자식 요소들을 모두 합친 높이) 브라우저 상의 높이가 더 커질 떄 데이터를 더 불러옴
if (isScrollEnded && !isLoading && photos.length < totalCount) {
onScrollEnded();
}
뷰포트에서 내가 감시하고 있는 애(observer)가 노출이 됐냐 안됐냐, 얼마나 됐냐를 가지고 판단하여 새로운 데이터를 불러오는 방법
const oberver = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting && !this.state.isLoading) {
// 감찰자 요소가 화면에 보인다면 && 로딩중이 아니라면 다음 데이터 요청
console.log('화면 끝!!', entry);
// 전체 데이터가 다 불러와지지 않았을 때만 데이터 요청
if (this.state.totalCount > this.state.photos.length) {
onScrollEnded();
}
}
});
},
{
threshold: 1,
// 0은 옵저버가 시작될 때,
// 1은 옵저버가 화면에 전부 들어왔을 떄
}
);
let $lastLi = null;
const $nextLi = $photos.querySelector('li:last-child');
// 감찰자를 계속 바꿔줌
if ($nextLi !== null) {
if ($lastLi !== null) {
oberver.unobserve($lastLi); // 옵저버에 마지막 요소들이 계속 쌓인다 - 없애줘야 함, 안그러면 기존 옵저버들이 보여질 때마다 데이터 요청 된다
}
$lastLi = $nextLi;
oberver.observe($nextLi);
}
무한 스크롤 구현 방법을 알고 싶었는데 이번에 배우게 되어서 좋았다.
이번 강의에서 특히 좋았던 점은 이미 렌더링된 요소들을 제외하고 렌더링 시키는 방법이었다. 노션 클론 프로젝트에서 페이지 목록 리스트들이 데이터가 변화할 때마다 모두 렌더링되어서 골치가 아팠는데 이번에 배운 걸 적용해봐야겠다.