Lazyloading을 구현 하면서 찾은 지식 Intersection Observer...

이건우·2022년 3월 2일
0
post-custom-banner

Intersection Observer는 Infinitiscroll, Lazyloading 등 다양하게 사용이 되는데 Intersection Observer를 사용하지 않는 대부분의 경우 3가지의 값을 비교 하게 된다 .

1. scrollHeight - 화면에 보이지 않는 총 높이까지 포함된 페이지의 높이
2. scrollTop - 이미 스크롤되어서 보이지 않는 구간의 높이
3. clientHeight - 사용자에게 보여지는 페이지의 높이

위 값중에서 scrollTop과 clientHeight을 합친 값이 scrollHeight 보다 크다면 스크롤 페이지의 끝에 닿았다고 판단을 하게 된다 .

그래서 scroll이벤트를 감지하는 event listner를 통해 스크롤이 끝에 닿았을 때에 추가 데이터를 받아 오는 방식이다 .

하지만 이벤트로 동작 시키게 되면 스크롤 이벤트가 발생 할 때마다 요청이 발생해서 엄청나게 요청이 많이 가게 된다 . 그래서 리소스 낭비를 막고자 두가지의 방법이 있는데 하나는 throttle을 사용하는 방법이고 다른하나는

 window.addEventListener("scroll", scrolling);
    return () => {
      window.removeEventListener("scroll", scrolling);
    };

이렇게 removeEventListener로 다시 지워주는 것이다 . 둘중에 편한 방법을 사용 하면 될 것 같다 .
나는 이 방법을 사용했다 .
하지만 이 방법 둘 다 완전히 최적화 했다고 보기에는 어렵다 어쨋건 이벤트가 발생은 하는 것이니까

그래서 이방법 보다는 Intersection Observer를 추천 하긴 한다

Intersection Observer
MDN의 내용에 따르면 타겟으로 관찰하고 있는 엘리먼트와 그 엘리먼트의 부모 혹은 상위 엘리먼트의 뷰포트가 교차되는 부분을 비동기적으로 관찰하는 API 라고 정의 되어 있다 .
Intersection Observer란 화면 상에 내가 지정한 타깃이 보이고 있는지를 관찰할 수 있도록 기능을 제공하는 API 인것이다 .

Intersection Observer의 장점 ?

  • Intersection Observer는 Scroll 이벤트와 달리 비동기적으로 실행되기 때문에, 디바운스나 쓰로틀을 구현하지 않아도 되어서 훨씬 나은 퍼포먼스를 보여준다.

  • 또한 매번 화면을 계산해서 그리는 reflow 현상을 일으키지 않기 때문에, 메인스레드에 주는 부담을 줄일 수 있다.

Intersection Observer 객체에서 사용 가능한 메서드

  1. observe(파라미터로 targetElement)
    파라미터로 넘긴 타겟 요소에 대한 관측을 담당한다. 동일한 옵저버 객체로 여러번 호출을 해서 다양한 타겟 요소에 대해 관측이 가능하다.

  2. unobserve(파라미터로 targetElement)
    타겟 요소에 대한 관측을 중지하는 역할을 담당.

  3. disconnect
    모든 타겟 요소에 대한 관측을 중지한다.

  4. takeRecord
    현재 관측 중인 모든 타겟 요소들을 배열 형태로 반환한다.

Intersection Observer API 사용 방법

// 타겟 요소 관측 시, 실행될 콜백 함수
const callback = (entries, observer) => {
  console.log('콜백함수');
};

// Observer 선언
const observer = new IntersectionObserver(callback, options);

// 타겟 요소 관측 시작
observer.observe(TargetElement);

// 타겟 요소 관측 중단
observer.unobserve(TargetElement);

// 모든 요소 관측 중단
observer.disconnect();

// 관측 중인 모든 요소를 배열 형태로 반환
observer.takeRecords();

Intersection Observer 의 기본구조

// 기본구조는 콜백함수와 옵션을 받는다.
const io = new IntersectionObserver(callback[, options])

Parameters
callback: 타겟 엘리먼트가 교차되었을 때 실행할 함수

  • entries: IntersectionObserverEntry 객체의 리스트. 배열 형식으로 반환하기 때문에 forEach를 사용해서 처리를 하거나, 단일 타겟의 경우 배열인 점을 고려해서 코드를 작성해야 합니다.
  • observer: 콜백함수가 호출되는 IntersectionObserver

options: option

const option = {
  root: null,
  rootMargin: 0px, 0px, 0px, 0px,
  threshold: 0,
}

root(viewport) : 타겟 요소와 교차 영역을 정의하기 위해 사용하는 상위 요소 프로퍼티다. 만약 값을 넣지 않거나 null일 경우에는 브라우저의 viewport(보여지고 있는 요소)가 root로 지정된다.

rootMargin : root 요소에 적용되는 margin 값을 정의하기 위한 프로퍼티. 지정한 값만큼 교차 영역이 계산되며 루트의 범위가 축소하게 된다.

thresholds : 콜백함수를 실행시키기 위한 루트 영역과 타겟 요소와의 교차 영역 비율을 지정하는 프로퍼티.
0.0과 1.0 사이의 값으로 지정한다. 값이 0이라면 타겟 요소가 교차 영역에 진입했을 때를 의미하며, 0.5라면 타겟 요소의 절반이 교차 영역에 들어왔을 때, 1.0이라면 완전히 교차 영역에 진입했을 때 콜백 함수가 실행된다.

📌 Intersection Observer 객체는 처음 생성될 때 타겟으로 지정한 요소 관측 시에 실행할 콜백 함수와 옵션 내용이 포함된 객체를 파라미터로 받는다. 옵션 객체는 문자 그대로 옵션이기 때문에 선택사항이며, 파라미터로 넘기지 않을 시 기본값이 적용된다.

📌 Intersection Observer는 화면에 띄어준 콘텐츠 중에 맨 마지막 요소를 관측해 콜백함수를 실행하는 원리로 무한스크롤을 구현하게 된다.

📌 타겟이 관측되었다면, 실행되는 콜백 함수 내에서 해당 요소에 대한 관측을 중지하고,
새로운 콘텐츠를 리스트에 추가한다. 그리고 다시 마지막 콘텐츠에 대해 관측을 시작하는 것이다.

📌 가장 보편적으로 사용되는 방법으로 list요소의 가장 아래에 빈 div요소를 생성하고, 그 요소에 ref를 달아주는 방법을 시용할 것이다. 이 ref를 통해서 교차시점을 확인할 수 있다.

👆 관찰자 생성

const defaultOption = {
  root: null,
  threshold: 0.5,
  rootMargin: '0px'
};

const observer = new IntersectionObserver(checkIntersect, {
        ...defaultOption,
        ...option
      }
                                       

✌ 관찰 대상 지정해주기

return (

  <Nav>
    ...
  </Nav>
  <ul>
    ...
  </ul>
  {isLoading && <p ref={loadingRef}>Loading...</p>}
</Wrap>

KeyPoint - 리스트 맨 아래에 ref로 관찰 대상을 만들어 주는 것이다

👌 관찰자를 만든다 .

const checkIntersect = useCallback(([entry], observer) => {
    if (entry.isIntersecting) {
      onIntersect(entry, observer);
    }
  }, []);

관찰 대상은 하나이므로 콜백함수의 인자로 들어오는 [entry]와 observer를 파라미터로 전달해주었다. 그리고 이 entry의 속성인 isIntersecting을 이용해 조건을 검사하고, 조건에 해당하면 콜백 함수를 실행한다.

isIntersectig: 관찰 대상의 교차 상태를 boolean 값으로 반환한다.

🖖 useEffect를 통해 관찰 대상 수시로 변경해주기 .

  1. useEffect를 사용해 데이터를 로드한다.
  2. 데이터를 로드하며 전역에서 관리하고 있는 isLoaded 상태 값을 바꿔준다.
  3. 화면 최하단에 있는 엘리먼트를 ref로 잡아 isLoaded 상태 값에 따라 랜더링시켜준다.
  4. useEffect를 사용해 타겟 요소의 상태 변경을 감지한다.
  5. useEffect내에서 Intersection Observer 인스턴스를 생성한다.
 useEffect(() => {
    let observer; // (1)beserver 변수를 선언해주고
    if (ref) { // (2) 관찰대상이 존재하는지 체크한다.
      observer = new IntersectionObserver(checkIntersect, { 
        ...defaultOption,
        ...option
      }); // (3) 관찰대상이 존재한다면 관찰자를 생성한다.
      observer.observe(ref); // (4) 관찰자에게 타겟을 지정한다.
    }
    return () => observer  && observer.disconnect(); // 의존성에 포함된 값이 바뀔때 관찰을 중지한다.
  }, [ref, option.root, option.threshold, option.rootMargin, checkIntersect]);

참조

profile
주니어 개발자 이건우 입니다 .
post-custom-banner

0개의 댓글