먹짱(쇼핑몰 프로젝트) - Intersection Observer로 무한스크롤 구현하기

ryan·2022년 5월 27일
0

개요

  • 내가 담당한 기능 중 상품 목록(전체, 카테고리 별)를 무한 스크롤로 구현해봤다.

  • 무한 스크롤을 선택한 이유는 두가지이다.

      1. 이번 프로젝트는 바닐라 스크립트로 SPA처럼 동작하는 것처럼 만들어보고 싶었고 새로고침이 발생하는 pagination보다 자연스럽게 렌더링되는 무한 스크롤이 사용자 경험에서 더 나을 것이라 생각했다.
      1. 무한 스크롤은 정말 많은 서비스에서 사용되고 있기 때문에 한번 꼭 해보고 싶었다. 실제 서비스에서 어떤 식으로 활용될 지 맛보기로나마 경험해보고 싶었다.

Intersection Observer의 개념

  • 스크롤이벤트와 pageYoffset을 이용하여 구현할 수 있는 방법 등 여러가지가 있는 걸로 막연히 알고만 있는데, 자바스크립트와 더불어 리액트에서도 잘 활용되고 있다는 Intersection Observer API를 이용하여 구현해보기로 했다.

Intersection Observer의 등장배경

  • MDN에서는 Intersection Observer을 아래와 같이 정의한다.

    타겟 요소와 상위 요소 또는 최상위 document 의 viewport 사이의 intersection 내의 변화를 비동기적으로 관찰하는 방법

  • 또한 MDN은 필요한 상황의 예시를 명시해놨다.

    • intersection 감지를 구현하면 영향을 받는 모든 요소를 알기 위해서 Element.getBoundingClientRect()와 같은 메서드를 호출하는 여러 이벤트 핸들러와 루프가 얽혀있었습니다. 모든 코드가 메인 스레드에서 실행되기 때문에, 이 중 하나라도 성능 문제를 일으킬 수 있습니다. 사이트가 이러한 테스트들과 함께 로드되면 상황이 더욱 나빠질 수 있습니다.
  • 내가 MDN 문서로 이해한 바로는 사용자가 웹상에서 이동하는 위치를 계속해서 반환하여 사용자의 intersection을 감지하는 방식(기존의 위치 정보를 활용한 스크롤 이벤트 등)은 문제가 발생하기 쉽고 복잡도가 높기 때문에, 더 나은 방식으로 사용자의 intersection을 감지할 수 있는 api를 제공한다는 의미이다.

    • 기존의 스크롤 이벤트를 제대로 활용하기 위해선 디바운싱과 쓰로틀링을 적절히 활용하여 불필요한 로딩이나 렌더링이 발생하지 않도록 해야하기 때문에 무한 스크롤을 구현하기 위해 다양한 개념을 이해하고 있어야 한다.

Intersection Observer가 사용되는 이유

  • 일단 공식문서에서 적어놓은 '비동기적으로 관찰한다'라는 것을 기억해둘 필요가 있다.

  • 인터섹션의 작동원리를 간단하게 표현하면 아래와 같다.

    1. 관찰할 Target을 정한다
    2. observe를 통해 관찰을 시작한다.
    3. target이 일정 threshold(가시성, 보여지는 정도)를 넘으면
    4. IntersectionObserver의 콜백함수가 실행된다.
    5. 이 과정이 백그라운드에서 비동기적으로 진행된다.
    6. 관찰 대상은 언제든지 바꿀 수 있으며 취소 또한 가능하다.
  • 더 이상 사용자의 위치 정보를 계속해서 반환할 필요가 없다.

  • 더 이상 불필요한 함수의 호출을 방지하기 위해 디바운싱, 스로틀링을 활용하지 않아도 된다.

  • 이러한 이유로 Intersection Observer가 무한 스크롤 구현에 더 적절한 API라고 나는 생각했다.

Intersection Observer의 활용

  • 내가 구현한 코드를 통해 구체적으로 어떻게 사용했는지 살펴보려고 한다.
  • 다른 코드는 차치하고 Intersection Observer 부분의 개요만 표현하자면 다음과 같다.
    1. Intersection Observer(콜백, threshold(가시성))를 호출한다.
    2. 보여지는 마지막 요소를 target으로 정하는 함수를 호출한다.
    3. 스크롤이 내려가면 Intersection Observer의 콜백이 실행된다.
    4. 콜백은 insertAdjacentHTML을 통해 html을 브라우저에 추가하고, 기존 관찰 대상을 취소한다. 그리고 다시 2번이 실행되는 함수이다.

코드

// intersectionObserver 콜백함수
const ioCallback = (entries, io) => {
  $article = document.querySelectorAll('#itemlist'); 
  // IntersectionObserver의 entries 객체를 구조분해할당하기
  const {isIntersecting, target} = entries[0]; 
  if (isIntersecting) { // 감지 상태를 확인함.
    // 기존 관찰 대상을 취소를 안한다면 계속해서 콜백함수가 실행됨.(관찰 대상을 최하단의 요소로 바꿔줘야 함)
    io.unobserve(target); 
    
    setTimeout(() => { // setTimeout은 백그라운드에 순차적으로 비동기 함수들이 실행되게 하기 위해 사용
      showContent(4, flag); // insertAdjacentHTML로 html을 띄우는 함수
      observeLastItem(io, $article); 
    }, 700);
  }
};

// 관찰 대상을 상품 목록의 마지막 요소로 변경하고 관찰 시작하는 함수
const observeLastItem = (io, items) => {
  let lastItem = items[items.length - 1];
  io.observe(lastItem); //
};

showContent(8); // 랜딩했을 때 최초 상품 8개 띄우기
const io = new IntersectionObserver(ioCallback, {threshold: 0.9}); 
// IntersectionObserver 호출
observeLastItem(io, document.querySelectorAll('#itemlist'));

화면

참고자료

무한 스크롤(Infinite scroll) 구현하기

profile
프론트엔드 개발자

0개의 댓글