IntersectionObserver

2023-11-10
ReactIntersectionObserver

Table of Contents

IntersectionObserver란?

new IntersectionObserver()를 통해 생성된 인스턴스는 관찰할 대상을 지정합니다. 관찰이란, 브라우저 내 viewport내에 요소를 감지하는 것을 뜻합니다. 즉, 어떠한 가시적 요소가 사용자에게 보여지는지 아닌지를 판별할 수 있게 됩니다.

기본적인 예제 및 개념은 mdn 및 좋은 블로그 글이 있습니다. 참고하시면서 적용하시면 될 것 같습니다.

Custom Hook으로 Viewport 내 요소 감지하기

어떠한 DOM element 하나를 props로 받아 해당 DOM이 viewport내에 표시되는지 확인하는 custom hook입니다.

import { useEffect, useState } from "react";
import type { RefObject } from "react";

type useIsInViewportParams = {
  ref: RefObject<HTMLElement>;
  threshold?: number | number[];
};

const useIsInViewport = ({
  ref,
  threshold = [0, 0.3, 0.5, 0.7, 1],
}: useIsInViewportParams) => {
  const [intersectionRatio, setIntersectionRatio] = useState(0);

  useEffect(() => {
    //  만약 props로 받은 ref의 current객체가 없다면 리턴합니다.
    if (!ref.current) {
      return console.error("Invalid reference");
    }
    //  ref의 current객체가 있다면 observer객체를 생성합니다.
    const observer = new IntersectionObserver(
      (entries) => {
        setIntersectionRatio(entries[0].intersectionRatio);
      },
      { threshold }
    );
    //  생성한 객체를 observing합니다.
    observer.observe(ref.current);
    return () => {
      //  DOM이 unmount 시 모든 observing을 해제합니다.
      observer.disconnect();
    };
  }, [ref]);

  return { intersectionRatio };
};

export default useIsInViewport;

활용하기

/App.css

h1 {
  margin-bottom: 100vh;
}
.box {
  width: 100%;
  height: 200px;
  border: 1px solid;
  margin-bottom: 30px;
}

/App.tsx

import "./App.css";
import { useRef } from "react";
import useIsInViewport from "./hooks/useIsInViewport";

function App() {
  const ref = useRef<HTMLDivElement>(null);
  const { intersectionRatio } = useIsInViewport({ ref: ref });
	console.log(intersectionRatio);
  return (
    <main>
      <h1>intersactionObserver</h1>
      <div className="box" ref={ref}></div>
    </main>
  );
}

export default App;
  • ref 객체를 넣어주고 그 객체에 대한 viewport 정보를 추출했습니다.

    콘솔이 많이 찍히는 이유는 strict-mode와 custom hook 내의 threshold 속성 때문입니다. threshold 배열값을 수정하시면 원하시는만큼 감지할 수 있습니다.

    활용하여 만든 무한스크롤