
Web API중 하나인 Intersection Observer API는 크롬 51버전부터 사용할수 있으며, 2016년 구글 개발자 페이지를 통해 소개되었다고 한다. MDN에서는 Intersection Observer의 필요성을 아래와 같은 예를 들어 설명하고 있다.
- 페이지 스크롤 시 이미지를 Lazy-loading(지연 로딩)할 때
- Infinite scrolling(무한 스크롤)을 통해 스크롤할 때 새로운 컨텐츠를 불러올 때
- 광고의 수익을 계산하기 위해 광고의 가시성을 참고할 때
- 사용자가 결과를 볼 것인지에 따라 애니메이션 동작 여부를 결정할 때
정리하자면, Intersection observer는 기본적으로 브라우저 뷰포트(Viewport)와 설정한 요소(Element)의 교차점을 관찰하며, 요소가 뷰포트에 포함되는지 포함되지 않는지, 더 쉽게는 사용자 화면에 지금 보이는 요소인지 아닌지를 구별하는 기능을 제공한다.
위에서 intersection observer는 target element가 화면에 노출되었는지 여부를 간단하게 구독할 수 있는 API라고 정리했다.
만약 intersection observer를 사용하지 않고 기능을 구현한다면, scroll이 일어날 때 마다 특정 element가 화면에 존재하는지에 대한 여부를 계속 계산하는 코드를 만들어 줘야할 것이다.
// 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>