[Javascript] Intersection Observer API란?

해피몬·2023년 9월 16일
post-thumbnail

Intersection Observer API란?

Web API중 하나인 Intersection Observer API는 크롬 51버전부터 사용할수 있으며, 2016년 구글 개발자 페이지를 통해 소개되었다고 한다. MDN에서는 Intersection Observer의 필요성을 아래와 같은 예를 들어 설명하고 있다.

  • 페이지 스크롤 시 이미지를 Lazy-loading(지연 로딩)할 때
  • Infinite scrolling(무한 스크롤)을 통해 스크롤할 때 새로운 컨텐츠를 불러올 때
  • 광고의 수익을 계산하기 위해 광고의 가시성을 참고할 때
  • 사용자가 결과를 볼 것인지에 따라 애니메이션 동작 여부를 결정할 때

정리하자면, Intersection observer는 기본적으로 브라우저 뷰포트(Viewport)와 설정한 요소(Element)의 교차점을 관찰하며, 요소가 뷰포트에 포함되는지 포함되지 않는지, 더 쉽게는 사용자 화면에 지금 보이는 요소인지 아닌지를 구별하는 기능을 제공한다.

💡 Intersection Observer 사용이유

위에서 intersection observer는 target element가 화면에 노출되었는지 여부를 간단하게 구독할 수 있는 API라고 정리했다.
만약 intersection observer를 사용하지 않고 기능을 구현한다면, scroll이 일어날 때 마다 특정 element가 화면에 존재하는지에 대한 여부를 계속 계산하는 코드를 만들어 줘야할 것이다.

사용예시

demo

// useIntersectionObserver.ts
import { useEffect, useState } from 'react';

interface useIntersectionObserverProps {
  root?: null;
  rootMargin?: string;
  threshold?: number;
  onIntersect: IntersectionObserverCallback;
}

export default function useIntersectionObserver({
  root,
  rootMargin = '0px',
  threshold = 1,
  onIntersect,
}: useIntersectionObserverProps) {
  const [target, setTarget] = useState<HTMLElement | null | undefined>(null);

  useEffect(() => {
    if (!target) return;

    const observer: IntersectionObserver = new IntersectionObserver(
      onIntersect,
      { root, rootMargin, threshold },
    );
    observer.observe(target);

    return () => observer.unobserve(target);
  }, [onIntersect, root, rootMargin, target, threshold]);

  return { setTarget };
}
// useIntersectionObserver 사용
  const onIntersect: IntersectionObserverCallback = ([{ isIntersecting }]) => {
    if (isSearching) return;
    if (isIntersecting) getMoreItem();
  };
  const { setTarget } = useIntersectionObserver({ onIntersect });

  return (
    <ul className={styles.container}>
      {residenceList?.map((el, idx) => (
        <SearchItem
          key={idx}
          residence={el}
          keyword={keyword}
          setInputText={setInputText}
        />
      ))}
      {isSearching && (
        <span className={styles.loading}>
          <LoadingSpinner />
        </span>
      )}
      {!isSearching && hasNextPage && (
        <span className={styles.ellipsis} ref={setTarget}>
          <AiOutlineEllipsis />
        </span>
      )}
    </ul>
profile
슬기로운개발생활🤖

0개의 댓글