POB_TIL 0513 : Intersection observer

이지훈·2022년 5월 12일
0

프리온보딩_TIL

목록 보기
8/22

무한스크롤을 해야한다.

scroll event vs intersection observer

간단히 가장 끝에 있는 요소까지 스크롤하면 새로운 목록을 불러와 이어붙이는것이다.
내가 찾아본 바로는 크게 두가지 방법이 있다. 하나는 스크롤 이벤트를 이용하는것이고 다른 하나는 intersection observer라는 기능을 이용하는것이다. 이 중 내가 사용한 기능은 intersection observer이다. 그 이유는 다음과 같다.

  1. scroll event는 스크롤에 따라 이벤트가 굉장히 자주 많이 발생한다.
    모든 스크롤에 동작을 실행하는건 비효율적이기때문에 이를 통제하기 위해서는 debounce와 throttle같은 처리를 해주어야한다.
  2. scroll event에서 좌표를 가져오기 위해 getBoundingClientRect()등을 실행하면, 많은 리플로우 현상이 발생하고 이는 성능 저하로 이어진다.

이러한 이유로 intersection observer를 사용해보기로 했다. 사용해보니 정밀한 좌표값보다 마지막 요소가 화면에 표시되었는지 아닌지가 필요한 무한스크롤 같은 기능은 intersection observer가 더 좋아보였다. react와 잘 어울리기도 하다.

intersection observer

MDN의 Intersection Observer API 문서

intersection observer api는 타겟 요소와 상위 요소 또는 최상위 document 사이의 intersection 변화를 비동기적으로 관찰하는 방법입니다

root값으로 넘겨줄 수 있는 상위 요소와, observer로 감시중인 타겟 요소 사이의 intersection을 비동기적으로 관찰하여 감시중인 타겟이 root요소의 viewport에 들어가거나 나가는것에 따라 콜백을 실행한다.

예제 코드로 보자면,

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

let observer = new IntersectionObserver(callback, options);
observer.observe(target);

root: 기준이 되는 상위 요소
rootMargin: 기준 요소로부터 보여지는 영역까지의 마진
threshold: 대상 요소가 root요소 내에 얼마나 보여질 때 콜백이 실행될 것인지를 결정. 0~1 사이로 1이면 100% 보여질 때 실행. 배열로 [0, 0.3, 1] 이런식으로 여러 구간마다 콜백이 실행되게 할 수도 있다.

콜백은 observe한 대상 entry배열과 observer를 파라미터로 가지는 함수로

let callback = (entries, observer) => {
  entries.forEach(entry => {
    // Each entry describes an intersection change for one observed
    // target element:
    //   entry.boundingClientRect
    //   entry.intersectionRatio
    //   entry.intersectionRect
    //   entry.isIntersecting
    //   entry.rootBounds
    //   entry.target
    //   entry.time
  });
};

이렇게 구성할 수 있다. observer.observe()로 관찰대상을 추가할수도 있고 unobserve()로 관찰을 중지하거나 disconnect()로 모든 요소의 관찰을 중지할 수도 있다.

문제

intersection observer를 사용하며 조금 문제가 있었는데, 일단 실행은 잘 됐다. 등록한 콜백에 따라 마지막 요소가 화면에 보이면 다음 요소를 불러오는 함수를 실행했고, 다음 요소를 목록에 추가해 늘어난 뒤 다시 마지막 요소의 ref에 intersection에 사용될 ref를 넘겨주어 intersection을 감지했다.
그런데 이 콜백이 의도한대로 맨 마지막 요소의 화면 표시에만 실행되지 않고 맨 처음 마운트할때도 동작하고 스크롤을 넘길때도 여러번 동작하는 등 의도치않은 실행이 너무 많았다. 이걸 컨트롤하기위해 entry.intersectionRatio를 확인해 체크하는 로직을 추가하기도 했지만 완전히 해결할 순 없었다.
결국 갖은 노력에도 문제의 원인을 찾지 못하고 react-use에 있던 useIntersection을 사용해 해결했다(내가 작성한것과 크게 다른건 모르겠는데 일단 됐다).
지금 보니 MDN문서의

Intersection observer 의 컨셉과 사용
Intersection Observer API는 다음과 같은 상황에 호출되는 콜백을 생성하는 기능을 제공합니다:
(1) 대상(target) 으로 칭하는 요소가 기기 뷰포트나 특정 요소(이 API에서 이를 root 요소 혹은 root로 칭함)와 교차함.
(2) observer가 최초로 타겟을 관측하도록 요청받을 때마다.

이 부분이 문제가 아니었을까? observer가 등록되며 콜백이 실행된것이고 새로운 요소가 추가된 뒤에도 ref를 옮기며 새로 observer가 관측을 하게되어 콜백이 중복해서 실행된.. 그런느낌이든다. 다음에 다시 테스트해봐야겠다.

도움

profile
안녕하세요! 대학교 졸업한 이지훈입니다.

0개의 댓글