본문 바로가기
Frontend/React

[React] Intersection Observer API로 무한 스크롤 구현

by yerin.dev 2024. 1. 27.

무한 스크롤

 

무한 스크롤이란 데이터를 끊김없이 제공하는 방식이다.

페이지네이션도 많은 양의 데이터를 보여줄 때 효과적이지만, 모바일 환경 같은 경우에는 끊김없이 데이터가 연속적으로 이어지는 것이 조금 더 나은 사용자 경험에 기여할 수 있다. 페이지네이션은 버튼을 눌러 페이지를 이동해 새로운 데이터를 보여준다면, 무한 스크롤을 사용하면 페이지 이동 없이 데이터를 연속적으로 보여줄 수 있기 때문이다.

무한 스크롤이라고 해서 모든 데이터를 한꺼번에 가져오는 것은 아니다. 페이지네이션과 마찬가지로 일정량의 데이터를 fetch하고, 화면의 끝에 다다르면 새 데이터를 fetch한다.

 

이번 프로젝트에 무한 스크롤을 구현하면서 공부한 것을 정리해보고자 한다.

 

 

리액트에서 무한 스크롤을 구현하는 방법들

 

  1. scroll event
    사용자의 스크롤을 감지하여 페이지 끝에 다다르면 새롭게 데이터를 불러온다.
  • 컴포넌트를 참조하여 스크롤 이벤트를 감지하다가
  • 컴포넌트의 scrollHeight(스크롤 할 수 있는 최대 화면 높이) == offsetHeight(컴포넌트 높이, border까지 포함) + scrollTop(화면 최상단에서 얼마나 scroll 되어 있는지) 이 되면 새롭게 데이터를 불러온다.
  • 방식 자체는 간단하지만 scroll event 자체를 throttle 같은 방식으로 최적화해줘야 한다. (throttle 외에 requestAnimationFrame을 이용해서 최적화할 수도 있다고 한다.)

 

 

참고 이미지들

offsetHeight와 clientWidth의 차이. offsetWidth는 border까지 포함.
scrollHeight

 

 

  1. react-infinite-scroll-component 라이브러리
    무작정 라이브러리로 해결하는 것보다 다른 방식으로 해보면서 배운 뒤에 사용하는 것이 나을 것 같아서 이번에는 pass.
  2. IntersectionObserver API
    내가 이번 프로젝트에서 무한 스크롤을 구현한 방식!

 

 

IntersectionObserver API

 

설정한 타겟요소(관찰대상)와 뷰포트의 교차여부를 비동기적으로 관찰(observe) 하는 API. Docs

 

사용 방법

// 1. IntersectionObserver를 생성하며 콜백함수를 넘긴다. 
const observer = new IntersectionObserver(observerCallback);

// 2. 생성된 observer가 타겟요소를 관찰하도록 한다. 
observer.observe(target);

 

 

끝! 너무나 간단하다. 무한스크롤을 구현하려면 콜백함수를 적절히 넘기기만 하면 될 것이다.

 

 

 const observerCallback = (entries) => {
    entries.forEach((entry) => {
      if (entry.isIntersecting && hasNextPage) {
        fetchNextPage();
      }
    });
  };

 

 

나는 @tanstack/react-queryuseInfiniteQuery를 이용했기 때문에 코드가 간결하지만 직접 구현하려면 더 복잡할 것이다.
아무튼, entries는 배열로, 타겟 하나 당 하나의 엔트리에 해당한다고 보면 될 듯하다.

isIntersecting은 교차 여부이다. 그래서 배열 각각의 요소(타겟)에 대해서 isIntersecting 교차되면 -> 데이터를 가져와라! 는 구조인 것이다.

다만 다음 페이지가 있을 때만 다음 페이지를 불러오도록 한다. (useInfiniteQuery야 고마워)

 

 

설정할 수 있는 옵션들

 

페이지 가장 밑에 도달했을 때 콜백함수를 부르는 게 일반적이겠지만(그래서 나는 옵션을 생략했다).

페이지 70퍼센트에 도달했을 때, 80퍼센트에 도달했을 때 등 세밀하게 그 수치를 조절할 필요가 있다면 옵션을 주면 된다.


root : 관찰자 라고 볼 수 있다. defaultnull 인데 이 경우 브라우저의 viewport가 사용된다.
rootMargin : 바깥의 여백을 설정해서 범위 수정 가능.
threshold : 교차 정도. 0 이면 타겟이 아직 뷰포트에서 보이지 않을 것이고 80퍼센트면 80퍼센트가 교차하고 있을 것이다. 0부터 1까지의 숫자를 넣을 수 있고, 배열도 넣어서 여러번 실행되도록 할 수도 있다.


그 외의 자세한 내용은 잘 정리된 블로그가 있어서 링크로 대체한다. 필요할 때 가서 참고하면 좋을 듯하다!

 

 

 

참고

 

https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API
https://heropy.blog/2019/10/27/intersection-observer/