HomeAboutMeBlogGuest
© 2025 Sejin Cha. All rights reserved.
Built with Next.js, deployed on Vercel
💌
JJong’s Archive
/
🌞
JS
/
무한 스크롤

무한 스크롤

Status
Done
Tags
날짜
Oct 30, 2023 05:00 AM
무한 스크롤?
⇒ 컨텐츠를 페이징하는 기법 중 하나로, 아래로 스크롤하다 컨텐츠의 마지막 요소를 볼 즈음 다음 컨텐츠가 있으면 불러오는 방식
⇒ 프론트엔드에서 많이 쓰는 기법인 이미지 지연 로딩에 쓸 수 있다
⇒ but. 상황에 따라 무한 스크롤보다 직접 불러오는 인터렉션(ex. 더보기 버튼)을 통해 로딩하는게 나을 수 있다
 
[구현 방법1] window의 scroll 이벤트를 통해 스크롤링이 일어날 때마다 화면 전체의 height와 스크롤 위치를 비교하는 방식
[구현 방법2] intersection observer
 

 
[API]
  • https://kdt-frontend.programmers.co.kr/cat-photos?_limit={limit}&_start={start}
    • {limit} : 한번에 가져올 갯수
      {start} : 가져올 시작 위치
  • 응답
    • id, imagePath, cats, photo_in_cats(id, name, colors, birthday, profileImage)
    •  

구현방법1 코드
const fetchPhotos = async () => { const {limit, start} = this.state this.setState({ ...this.state, isLoading: true }) const photos = await request(`/cat-photos?_limit=${limit}&_start=${start}`) this.setState({ ...this.state, start: start+limit, photos: this.state.photos.concat(photos), isLoading: false }) }
  • isLoading으로 패치 전후로 로딩여부를 세팅하고, 로딩이 끝나면 사진을 불러오도록 처리한다
 
this.render = () => { if (!isInit) { $list.innerHTML = ` <ul class="photoList_photos"></ul> ` isInit = true } const $photos = $list.querySelector('.photoList_photos') this.state.photos.forEach(photo => { const { id, imagePath } = photo if($photos.querySelector(`li[data-id="${id}"]`) === null) { const $li = document.createElement('li') $li.setAttribute('data-id',id) $li.setAttribute('style',"list-style: none; min-height: 500px;") $li.innerHTML = `<img width="200" src="${imagePath}"/>` $photos.appendChild($li) } }) }
렌더링할 때마다 innerHtml을 지정하면 항상 사진이 처음부터 보여진다
그래서 처음에만 innerHtml을 하고 그 이후에는 새로 추가된 사진만 li에 담아 하나씩 appendChild한다
 
window.addEventListener('scroll', () => { const { isLoading, totalPhotoCount, photos } = this.state const isScrollEnded = window.scrollY + window.innerHeight >= document.body.scrollHeight if (!isLoading && isScrollEnded && totalPhotoCount > photos.length){ console.log(window.scrollY, window.innerHeight, document.body.scrollHeight) onScrollEnded() } })
 
 

 
구현방법2 코드
const $li = document.createElement('li') $li.setAttribute('data-id',id) $li.style = "list-style: none; min-height: 500px" $li.innerHTML = `<img width="100%" height="100%" src="${imagePath}"/>` $photos.appendChild($li) } }) let $lastLi = $photos.querySelector('li:last-child') if ($lastLi && !isLoading && totalPhotoCount > photos.length) { photoObserver.observe($lastLi) }
  • $li.style 로 js에서 dom 객체의 style을 지정할 수 있다
  • $li.style = "list-style: none; min-height: 500px"
    • ⇒ 사진이 완전히 로딩 되기 전엔 사진들의 높이가 거의 없어서 한화면에 모든 사진이 다 나오게 된다
      최소 li 높이를 지정함으로써 로딩 중에도 화면에 안보이는걸 보장한다.
  • 불러온 것들 중에 마지막 사진을 담은 li를 관찰대상으로 한다.
    • 'li:last-child' : 구조 의사 클래스
 
const photoObserver = new IntersectionObserver((entries, observer)=>{ if (entries[0].isIntersecting) { console.log("마지막 보여짐, 사진 더 로딩합니당") observer.unobserve(entries[0].target) onScrollEnded() } })
  • 보여진다면 로딩, 로딩 이후에는 지금 li는 마지막 li가 아니므로 관찰 삭제하면서 나온다.