Intersection Observer API를 이용한 infinite scroll 만들기!

기록일기📫·2021년 7월 21일
6
post-thumbnail

이번 포스팅에서는 intersection oberserver API에 대해 알아보고, 이를 이용해서 infinite scroll을 간단히 구현해보자🙌

infinite scroll이란?

Infinite scroll은 말 그대로 '무한 스크롤'이라는 의미인데, 최근 인스타그램, 유튜브 등 대부분의 웹 어플리케이션에서 적극적으로 사용하고 있는 데이터 로딩 방식이다.

infinite scroll의 핵심은 전체 데이터를 한번에 받아 오는 것이 아니라, 현재 화면 기준으로 뿌려질 데이터만 받아 온다는 점에 있다.

유저가 스크롤을 통해 데이터의 끝(페이지 하단)에 도달하면 새로운 컨텐츠를 받아 온 뒤 덧붙여서 화면을 업데이트 방식으로 진행된다. (ex : 유튜브 댓글, 인스타 피드 등을 생각해보자)

이러한 방식을 사용하면 모든 데이터를 한번에 로딩 하는 것 보다 퍼포먼스 측면에서 좋기 때문에 자연스레 서비스를 이용하는 유저 경험도 좋아지게 된다.


intersection Observer

infinite scroll을 어떻게 구현할 수 있을까? 대표적인 방식은 dom의 intersection observer API를 이용한 방식이다.

intersection Observer? 🤷‍♀️

intersection observer란 쉽게 말해서 dom에 특정 element에 대해 감시자인 observer를 설정하는 것이다.

그리고 해당 element가 특정 viewport에 진입하거나 나갈때, 혹은 특정 부분만큼 두 요소가 교차할때 마다 콜백 함수를 실행시킨다.

말로 설명하면 조금 난해할 수 있으니, MDN 예제 코드를 같이 코드를 통해 이해해보자.

let options = {
  root: document.querySelector('#scrollArea'),
  rootMargin: '0px',
  threshold: 1.0
}

let observer = new IntersectionObserver(callback, options);

observer를 생성할때는 인자로 option과 콜백 함수를 전달할 수 있는데, 각각의 인자에는 다음과 같은 내용이 담긴다.

  1. option은 말 그대로 어떤 조건에서 이벤트를 발생 시킬지에 대한 내용이고, 콜백 함수를 실행시킬 트리거 조건이 된다.
  1. 콜백 함수에는 이벤트 발생 시 어떠한 행동을 할 지에 대한 내용이 담긴다.

즉 intersection observer를 통해서 어떤 조건이 충족되면(option), 어떤 행동을 할건지(callback) 설정할 수가 있는 것이다! (option property에 대한 자세한 내용은 여기를 참고하세요!)

observer 연결

observer 생성을 하면 observer가 어떤 대상을 감시하기 시작 할 지 target을 설정할 수 있다.

let target = document.querySelector('#listItem');
observer.observe(target);

이렇게 target 지정까지 마치게 되면, 해당 observer가 target에 대해 모니터링을 시작하게 된다. 즉 위와 같은 경우는 listItem이 scrollArea영역 내에 들어왔을때, 등록한 콜백 함수를 실행하게 된다!

이 이상의 자세한 내용은 mdn에 상세히 설명되어 있으므로 참고하도록 하자.

https://developer.mozilla.org/ko/docs/Web/API/Intersection_Observer_API

이제 어떻게 infinite scroll을 구현 할 수 있을지 조금 감이 오는 것 같다.😊


시작

우리는 openLibrary api를 이용하여 특정 제목의 책을 검색하고, 검색 목록에 infinite scroll을 적용 해 볼것이다.

진행 순서는 다음과 같다.

  1. api 호출을 통해 책 목록을 받아옴
  2. 현재 화면에 보이는 마지막 책에 observer를 등록
  3. element가 viewport에 들어오면 api를 다시 호출
  4. 새로운 데이터를 덧붙여 화면을 rendering 해줌으로써 infinite scroll을 구현

api 호출을 통해 책 목록을 받아오기

우선, 해당 api를 호출해서 책 목록을 받아오자!

받아온 책의 제목(title)을 books에 state로 지정하고 api 호출을 통해 돌려주는 custom hook이다. setBooks 내부의 내용을 보면, api 호출을 통해 받아온 데이터를 기존의 데이터에 덧붙여 return하고 있음을 확인할 수 있다.

서버 통신 부분은 지금 중요한 부분은 아니니, 이정도만 살펴보고 넘어가겠다.

현재 화면에 보이는 마지막 책에 observer 등록

books를 순회하면서 마지막 원소에 useRef에 lastBookElementRef callback 함수를 전달하여 준다. lastBookElementRef에서는 해당 element가 viewport 내에 들어오면 다시 api를 호출할 수 있도록 할 것이다.

element가 viewport에 들어오면 api를 다시 호출 & re-rendering

이제 이 부분이 infinite scroll의 핵심✨이다!

11~24번째 라인을 보자. lastBookElementRef는 우리가 앞서 마지막 책에 달아놓은 ref callback이며, node로 해당 element가 전달되게 된다.

유저가 스크롤을 통해 마지막 element에 도달하면 기존의 observer를 disconnect 시키고 새로운 observer를 연결한 다음 콜백 함수를 전달하여 해당 element가 화면에 나타나게 되면 트리거될 이벤트를 전달하는 부분이다.

 if (entries[0].isIntersecting && hasMore) {
          setPageNumber((prevPageNumber) => prevPageNumber + 1);
        }

우리는 intersectionObserver의 isIntersecting값을 통해 해당 element가 화면에 보이고 있는지를 판단할 수 있다. (MDN 설명 링크)

The IntersectionObserverEntry interface's read-only isIntersecting property is a Boolean value which is true if the target element intersects with the intersection observer's root

이렇게 우리는 해당 element가 화면에 보여지면 pageNumber state를 변경시킴으로써 새로운 데이터를 불러오게 된고, 다시 마지막 element에 새로운 observer를 연결시키면서 infinite scroll을 구현할 수 있다!

0개의 댓글