infiniteScroll 기법

2023. 7. 4. 13:16zerobase/react

728x90

 

수많은 정보들을 로드하기 위해서 브라우저는 무한 로딩에 빠질 수가 있다.

한번에 많은 양의 데이터들을 로드해야하니 속도는 당연히 느려질 수 밖에 없을 것이다.

이러한 방법을 해결하기 위해서 데이터를 분할하여 보여주는 방법이 있다. 크게 2가지가 있는데, 페이지네이션과 무한스크롤이라고 하는 방법이 있다.

 

페이지네이션은 페이지를 번호로 분할해서 넘기면서 볼 수 있는 방법이고

무한스크롤은 스크롤을 내리면서 무한으로 정보가 나오는 방법이다.

 

오늘은 무한스크롤에 대해서 알아보려고 한다.

 

무한스크롤의 장점과 단점

장점

- 컨텐츠 탐색이 쉬워짐

- 사용자 참여가 쉬워짐

- 다음 콘텐츠를 보기 위한 추가 클릭이 필요없고 페이지 로드 시간이 짧음

- 모바일일 때 더 유용하게 적용됨

- 화면이 작을수록 스크롤이 길어지기 때문에 모바일 환경에서 콘텐츠를 보여주기 직관적이고 사용하기 쉬움

 

단점

- 페이지 성능이 느려임

- 검색 및 원래 위치로 돌아오기 힘듦

- 스크롤 막대가 데이터의 양을 반영하지 못함

- 푸터를 찾기 어려움

 

무한스크롤 구현 방법

scroll event

import renderList from './renderList';

const app = document.querySelector('#app');
const fetchMoreTrigger = document.querySelector('#fetchMore');
let page = 0;


const fetchMore = async () => {
  const target = page ? fetchMoreTrigger : app;
  target.classList.add('loading');
  await renderList(page++);
  target.classList.remove('loading');
};

const onScroll = e => {
  const {
   scrollHeight,
   scrollTop,
   clientHeight,
  } = e.target.scrollingElement;
  if (scrollTop + clientHeight === scrollHeight) {
    fetchMore()
  } 
};

document.addEventListener('scroll', onScroll);
fetchMore();

1. addEventListner로 scroll 이벤트를 받고, onScroll 함수를 실행시킴

2. 함수는 e를 인자로 받고, 구조분해할당으로 scrollHeight, scrollTop, clientHeight를 선언하고 할당받음

3. scrollTop + clientHeight === scrollHeight  조건문은 스크롤바 수직 위치 +  유저가 보고 있는 창의 높이를 더한것이 현재 scrollHeight와 같은지 판별하는 조건문임

4. 참이라면 fetchMore()을 통해 데이터들을 더 불러옴

5. fetchMore()은 async await로 데이터를 비동기 처리로 불러오게 됨

 

하지만 이 방법은 스크롤 단위 1마다 이벤트리스너가 실행되어 규모가 큰 프로젝트에서 스크롤 할 양이 많아진다면, 선응이 저하 될 수 있음

 

이를 보완하기 위해 throttle과 debounce가 있음

 

throttle

이벤트에 의한 콜백을 일정시간 뒤에 호출하는 기법

var throttler;
window.onscroll = () => {
  // throttle
  if(!throttler) {
    throttler = setTimeout(() => {
      throttler = null; 
      console.log('throttle');
    }, 200);
  }
}

 

0.2초마다 throttle이 콘솔에 출력됨

 

debounce

연이어 호출되는 콜백 중 마지막 혹은 처음 것만 호출하도록 하는 기법

const debounce = (event, delay) => {
  let timeoutId = null;
  return (...args) => {
    clearTimeout(timeoutId);
    timeoutId = setTimeout(event.bind(null, ...arg), delay);
};

// 코드 생략 ... 
  
document.addEventListener('scroll', debounce(onScroll, 500));
fetchMore();