ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Javascript - 무한 스크롤 만들기
    Javascript 2023. 7. 17. 01:26

     

    🔔 서론

    인스타그램, 트위터, 페이스북 등의 sns를 이용하다 보면 스크롤을 내릴 때 일정 개수 이상의 피드를 보고나면 로딩중이라는 ui가 표시되면서 새로운 피드를 불러오는 경험을 겪어본 적이 있을 것이다. 수십 수백개의 데이터를 한번에 불러오면 사용자에게 큰 부담을 주기 때문에 소수의 데이터만 미리 불러두고 스크롤을 하면 추가로 데이터를 불러오는 방식으로 무한으로 스크롤을 할 수 있는 것이다. 오늘 알아볼 내용은 무한 스크롤을 구현하는 내용이다. 무한 스크롤이란, 컨텐츠를 페이징하는 기법 중 하나로 아래로 스크롤하다 컨텐츠의 마지막 요소를 볼 즈음 다음 컨텐츠가 있으면 데이터를 불러오는 방식으로 주로 sns에서 사용된다.

    무한 스크롤 구현 방식은 크게 두 가지로 알아보자.

    1. window의 scroll 이벤트를 통해 스크롤링이 일어날 때마다 화면 전체의 height와 스크롤 위치를 통해 스크롤이 컨텐츠 끝 즈음에 도달했는지 체크해서 처리하는 방식
    2. intersection observer 방식

    실습을 하기 위해 진행했던 프로젝트는 고양이 사진을 불러오는 api를 사용해서 App과 PhotoList 컴포넌트 두개로 구성된 간단한 프로젝트이다.

    전체 코드를 공개할 수 없는 상황이기에 핵심 키워드가 되는 부분 코드들만 보면서 알아보도록 하자.


    📌 1. window scroll 이벤트

    window 의 scroll 이벤트를 이용해서 무한 스크롤을 구현하는 방법을 간단하다. 스크롤 이벤트가 발생할 때 마다 현재 스크롤의 위치와 화면에 렌더링된 전체 높이를 비교해 현재 스크롤이 끝에 거의 도달 했다면 다음 데이터를 요청해 화면에 렌더링 하는 방식으로 구현하면 된다.

    window.addEventListener('scroll', () => {
      const isScrollEnded = (window.innerHeight + window.scrollY) + 100 >= document.body.offsetHeight;
    
      if (isScrollEnded) {
        // 데이터 요청
      }
    })

    window의 현재 높이(window.innerHeight)와 스크롤된 Y축값(window.scrollY)를 더하면 전체 컨텐츠에서 스크롤이 얼마나 되었는지 확인할 수 있다. 100을 더해 준 이유는 스크롤이 화면 끝에 닿았을 때 데이터를 요청하는 것보다 끝에 다다랐을 때 쯤 불러오는 것이 ux적으로 보기 좋기 때문이다.

    다만, window scroll 이벤트를 이용해서 무한 스크롤을 구현하면 생기는 단점이 있는데, 스크롤을 할 때마다 이벤트가 발생하기 때문에 성능적인 면에서 떨어질 수도 있다는 것이다. 물론 스크롤 이벤트에 debounce를 걸어 마지막 이벤트만 발생시키는 방법도 있겠지만, 비교적 최근에 나온 api를 사용해서 다르게 해결해보자.


    📌 2. Intersection Observer

    Intersection Observer API는 타겟 요소와 상위 요소 또는 최상위 document의 viewport 사이의 intersection 내의 변화를 비동기적으로 관찰하는 방법이다. - MDN 공식문서

    더군다나 공식문서에서 무한 스크롤을 구현할 수 있는 방법중 하나라고 소개까지 하고 있어 사용하지 않을 이유가 없다.

    🤔 오호라

    Intersection Observer API는 요소를 감시하고, 해당 요소가 유저에게 표시되는 시점을 알려주는데 이를 이용해서 구현을 진행해보도록 하자.

    1. 우선, 요소를 감시할 observer를 생성해주고, $사진_리스트의 li태그중 마지막 요소를 가져와 observer에게 관찰하게 한다.
    2. observer를 생성할 때 두 가지 인자를 받는데, 첫 번째 인자는 관찰중인 요소에 접근할 때 호출할 콜백함수를 넣고, 두 번째 인자로는 옵션을 넣는데 여기서는 threshold라는 요소의 가시성 퍼센티지를 나타내는 속성을 추가하도록 하겠다. 예를들어 threshold: 1 의 속성을 넣으면 요소가 100% 모두 화면에 노출 되었을 때 콜백함수를 실행하고, 0.5로 설정해두면 50%만 노출되어도 콜백함수를 실행하는 속성이다.
    3. 또한, 무한 스크롤링을 하면서 데이터를 추가로 계속 받아올 것이기 때문에 새로운 데이터가 들어올 때마다 관찰중인 요소도 바뀌어야 할 것이다. 따라서 render가 이루어 질 때마다 관찰중이던 마지막 li태그를 관찰 해제하고 현재 렌더링된 마지막 li태그를 관찰하도록 한다.
    // observer 생성
    const observer = new IntersectionObserver(items => {
      entries.forEach(item => {
        // item이 화면에 노출되었다면
        if (item.isIntersecting) {
          // 새로운 데이터 요청
        }
      })
    }, {
      // 화면에 50%만 노출되어도 callback 함수 실행
      threshold: 0.5
    })
    
    let $lastLi = null;
    
    this.render = () => {
      //...
      
      // 사진리스트의 li태그중 마지막 요소
      const $nextLi = $사진_리스트.querySelector('li:last-child');
      
      if ($nextLi !== null) {
        // 이전의 관찰중인 마지막 li태그 존재시 관찰 해제
        if ($lastLi !== null) {
          observer.unobserve($lastLi);
        }
    
        $lastLi = $nextLi;
        // 마지막 li태그 관찰
        observer.observe($lastLi);
      }
    }
    
    this.render();

    이렇게, Intersection Observer API를 이용해서 무한 스크롤링을 구현하는 방법까지 알아보았다.

Designed by Tistory.