리팩토링 하는 과정에서 scroll event에 관련된 아주 유용한 api가 있다고 하여 찾아보고 적용해 보았습니다.

Intersection Observer API

브라우저의 뷰포트(상위 요소)와 설정한 요소(대상요소)의 교차점을 비동기적으로 관찰하여 요소가 뷰포트에 포함되는지 안되는지 구별하는 기능을 제공합니다.

How to use?

1. new IntersectionObserver() 생성자를 초기화하고, 설정요소(관찰대상)를 지정합니다.

const observer: IntersectionObserver = new IntersectionObserver(callback, options)

observer.observe(설정요소)

2. 설정요소가 등록되거나 변화가 생기면 콜백이 호출됩니다. 콜백은 2개의 인수를 가집니다.

const observer: IntersectionObserver = new IntersectionObserver((entries, obsercer)=>{}, options)

entriesIntersectionObserverEntry 인스턴스의 배열이며, 아래와 같은 속성들을 가지고 있습니다.

boundingClientReact: 설정요소의 사각형 정보(DOMReactReadOnly)
intersectionReact: 설정요소의 교차한 영역 정보(DOMReactReadOnly)
intersectionRatio: 설정요소의 교차한 영역 백분율
(intersectionReact영역에서 boundingClientReact 영역까지 비율, number)
isInteresting: 설정요소의 교차 상태(boolean)
rootBounds: 지정한 루트 요소(브라우저의 뷰포트(상위 요소))의 사각형 정보(DOMReactReadOnly)
target: 설정요소(Element)
time: 변경이 발생한 시간정보(DOMHighResTimeStamp)

options 에는 아래와 같은 속성들을 가지고 있습니다.

root: 설정요소의 상위 항목이어야 하고, 설정이 안되어 있으면 기본값은 null로 브라우저 뷰포트입니다.
rootMargin: root의 주변 여백이며, css margin 속성과 유사한 값을 가지고 있습니다.
단위는 px 또는 %로 꼭 입력해야 합니다.
threshold: 설정요소가 어느정도 화면에 보일 때 observer를 실행시킬 지 설정요소 가시성의 백분율을 나타내는 숫자, 숫자배열입니다.
기본값은 0입니다.

3. obsever & unobserver & disconnect 메소드 호출

observer

설정요소의 관찰을 시작합니다.

const box = document.getElementById("RootBox");

observer.observe(box);

unobserver

설정요소의 관찰을 중지합니다.

const box = document.getElementById("RootBox");

observer.unobserve(box);

disconnect

IntersectionObserver 인스턴스가 관찰하는 모든 설정요소의 관찰을 중지합니다.

const box = document.getElementById("RootBox");

observer.disconnect();

refactory!

  • 첫번째 박스가 사라질 때 두번째 박스가 보여야 하는 이벤트를 이벤트 리스너를 통해 아래와 같이 구현했습니다.
  const onScroll = React.useCallback(() => {
    const Position = document.getElementById("RootBox");
    const scrollY = Position?.getBoundingClientRect().bottom;
    if (scrollY === undefined) return;
    if (scrollY < 0) {
      setHeight(true);
    } else {
      setHeight(false);
    }
  }, []);
  
  React.useEffect(() => {
    //add eventlistener to window
    window.addEventListener("scroll", onScroll, { capture: true });
    // remove event on unmount to prevent a memory leak with the cleanup
    return () => {
      window.removeEventListener("scroll", onScroll);
    };
  }, [onScroll]);
  • IntersectionObserver 로 구현했습니다.
const Positon = document.getElementById("RootBox");

  React.useEffect(() => {
    if (!Positon) return;
    const observer: IntersectionObserver = new IntersectionObserver(([entries]) => {
      if (!entries.isIntersecting) {
        setHeight(true);
      } else {
        setHeight(false);
      }
    });
    observer.observe(floorPosition);
  }, [Positon, height]);
  1. entries는 배열이기때문에 구조분해를 했습니다.
  2. entries의 isIntersecting의 속성을 통해 조건을 달아서 unobserver를 쓰지 않았습니다.
  3. isIntersecting은 설정요소가 화면에 보이면 true, 안보이면 false 이기 때문에 안보였을 때에 이벤트가 일어나야 하여, 상기와 같이 조건을 달았습니다.

결과물

첫번째 박스가 사라지면 나타나는 설정요소!

느낀점!

기존에는 이벤트 핸들러를 통해 스크롤 이벤트를 구현했기때문에 성능이슈 없이 사용 가능합니다.
확실히 코드가 짧아져서 가독성도 좋아졌습니다!

참조 :
Intersection Observer - 요소의 가시성 관찰
Intersection Observer API

profile
Whatever you want

0개의 댓글