[React] react-intersection-observer

bunny.log·2022년 5월 25일
0

Intersection Observer API 란?

어떤 Element가 화면(viewport)에 노출되었는지를 감지할 수 있는 API이며 이런 유용한 점을 이용해서 우리들은 무한 스크롤(Infinite Scroll)을 만들어볼 수 있습니다.

무한 스크롤을 구현할 때는 Scroll Event를 감지해서 유저가 화면 제일 끝에 도달했을 때 아이템을 더 불러오게끔 만들수도 있는데 굳이 Intersection Observer API를 사용하여 무한 스크롤을 구현하는 이유는 뭘까요?

  • Scroll Event를 사용해서 구현할 때 사용하는 debounce & throttle 을 사용하지 않아도 됩니다..
  • Scroll Event를 사용해서 구현할 때 구하는 offsetTop 값을 구할 때 는 정확한 값을 구하기 위해서 매번 layout을 새로 그리는데 이를 Reflow라 합니다. Intersection Observer를 사용하면 Reflow를 하지 않습니다.
  • Scroll Event를 사용하는것 보다 비교적 이해및 사용하기가 쉽습니다.

Intersection Observer Options

간단한 Intersection Observer 생성 예제

let observer = new IntersectionObserver(callback, options);

Intersection Observer를 생성할 때는 옵션을 설정할 수 있습니다.
옵션에는 root, rootMargin, threshold가 있는데요,

  • root : 이 옵션에 정의된 Element를 기준으로 Target Element가 노출되었는지 노출 되지 않았는지를 판단합니다. 기본값은 Browser Viewport이며, root 값이 null 또는 지정되지 않았을 때 기본값으로 설정됩니다.
  • rootMargin : root에 정의된 Element가 가진 마진값을 의미합니다. 사용법은 CSS의 margin 속성과 매우 유사합니다. threshold를 계산할 때 rootMargin 만큼 더 계산합니다.
  • threshold : Target Element가 root에 정의된 Element에 얼만큼 노출되었을 때 Callback함수를 실행시킬지 정의하는 옵션입니다. number 또는 number[]로 정의할 수 있습니다.
    number 로 정의할 경우, Target Element 의 노출 비율에 따라 Callback Function을 한번 호출할 수 있지만, number[] 로 정의할 경우, 각각의 비율로 노출될 때마다 Callback Function을 호출합니다.

예전에는 스크롤 이벤트를 구현하기 위해 scroll, Element.getBoundingClientRect() 등의 메서드를 사용해 하나하나 계산해서 값을 얻어야 했는데 scroll 이벤트의 경우 동기적으로 실행되기 때문에 이벤트 연속 호출, 렌더링 성능 저하 등의 문제가 있었다.

그러던 와중에 2016년 구글 개발자 페이지를 통해 IntersectionObserver가 소개됐다.
IntersectionObserver는 비동기적으로 실행되며 관찰 대상과 뷰포트의 교차점을 관찰하고, 뷰포트 안으로 들어오는 시점에 정보를 제공한다.

설치

$ npm i intersection-observer

IntersectionObserver 사용법

인스턴스 생성

const io = new IntersectionObserver(콜백함수, 옵션);

콜백함수 설정

const io = new IntersectionObserver((entries, observer) => {}, 옵션)

entries

관찰 대상의 여러 정보들이 배열로 담겨져 있다.
boundingClientRect 관찰 대상의 사각형 정보(DOMRectReadOnly)
intersectionRect 관찰 대상의 교차한 영역 정보(DOMRectReadOnly)
intersectionRatio 관찰 대상의 교차한 영역 백분율(intersectionRect 영역에서 boundingClientRect 영역까지 비율, Number)
isIntersecting 관찰 대상의 교차 상태(Boolean)
rootBounds 지정한 루트 요소의 사각형 정보(DOMRectReadOnly)
target 관찰 대상 요소(Element)
time 변경이 발생한 시간 정보(DOMHighResTimeStamp)

observer

대상을 지정하면 그 대상을 관찰하는 역할을 한다.

옵션 설정

let 옵션 = {
  root: document.querySelector('#scrollArea'),
  rootMargin: '10px 0 -20px 0', // root가 위로 10px 커지고 아래로 20px 작아진다. 
  threshold: 0.5 // 대상이 50% 보였을 때 실행
}

let io = new IntersectionObserver(콜백함수, 옵션);

root 뷰포트 대신 사용할 요소를 지정한다. 지정하지 않을 경우 브라우저 뷰포트로 설정된다.
rootMargin 마진을 설정하여 Root에서 지정된 뷰포트의 영역을 확장/축소할 수 있다.
threshold 뷰포트에 관찰 대상이 얼마나 보여야 observer를 실행할 지 설정할 수 있다. 숫자나 숫자 배열로 값을 설정할 수 있다.
25% 단위로 타겟 요소의 보일때마다 콜백함수를 호출하고 싶다면 [0, 0.25,0.5, 0.75, 1]로 설정하면 된다.

관찰 시작

const io = new IntersectionObserver((entries, observer) => {});

io.observe(관찰대상);

관찰 종료

io.disconnect();

React에서 사용

리액트에서 IntersectionObserver 사용 시, 관찰할 DOM 요소는 Ref를 사용해 참조를 만든다.

const observer = () => {
 const itemRef = useRef<HTMLDivElement[]>([]);
 
 const io = new IntersectionObserver((entries, observer) => {
   entries.forEach((entry) => {
     // 관찰 대상이 뷰포트에 들어왔을 경우
     if (entry.intersectionRatio > 0) {
       entry.target.classList.add("active");
     }
     // 관찰 대상이 뷰포트에 없을 경우
     else {
       entry.target.classList.remove("active");
     }
   });
 });

 // 관찰 대상 관찰 시작
 for (let i = 0; i < itemRef.current.length; i++) {
   io.observe(itemRef.current[i]);
 }
}
profile
나를 위한 경험기록

0개의 댓글