티스토리 뷰

1. 개요

 노마드 코더의 캐럿마켓 클론코딩 강의를 수강하였다. 이제 배포만 남았는데, 배포 전 마지막으로 강의를 통해 배웠던 것 중 특별히 기록할만한 것들을 정리해보려고 한다. 우선은 메인 페이지(상품 페이지)의 무한 스크롤이다.

 

2. IntersectionObserver

 

 처음에는 상품을 10개를 가져온다. 그리고 스크롤을 하면 트리거 역할을 하는 span 태그가 존재하고, 이것이 화면에 노출될 경우 상품을 추가적으로 받아온다. 이 때, 트리거 역할을 하는 컴포넌트가 화면에 노출될 경우 상품을 추가적으로 받아오는 것은 IntersectionObserver를 이용해 구현하였다.

 

const observer = new IntersectionObserver(callback, options);

 

IntersectionObserver의 동작 원리는 다음과 같다. IntersectionObserver는 생성 시 콜백 함수와 옵션을 인자로 받아 관찰자를 초기화한다. callback 함수는 (entries, observer) 형식으로 관찰 대상 요소의 상태와 관찰자 자신(observer)이 전달된다.

 

observer.observe(target);

 

그리고 observer.observe를 통해 대상 요소를 관찰 리스트에 추가할 수 있다. 이렇게 추가한 요소들이 callback 함수의 entries에 포함된다. 관찰 대상을 등록하면 브라우저가 비동기적으로 뷰포트와 요소의 상태를 평가하고 필요시 콜백 함수를 실행한다. 

 

observer.unobserve(target);
observer.disconnect();

 

더 이상 요소를 관찰할 필요가 없으면 unobserve 혹안 disconnect를 통해 관찰을 중단할 수 있다.

  • unobserve: 특정 요소에 대한 관찰을 중단
  • disconnect: 모든 관찰 대상을 해제

 

2-1. 뷰포트 (Viewport)

 뷰포트는 사용자가 현재 보고 있는 화면 영역을 의미한다. 웹 브라우저에서는 현재 보이는 브라우저 창 안의 콘텐츠 영역이 된다. 기본적으로 IntersectionObserver의 뷰포트는 후술할 options의 root 설정이 없다면 브라우저 뷰포트 (화면 영역)가 기본 root로 사용된다.

 

2-1. IntersectionObserver의 callback, options

 앞서 작성했듯, callback함수는 관찰 대상 요소가 뷰포트와 교차할 때 실행될 함수로,  (entries, observer) 형식으로 관찰 대상 요소의 상태와 관찰자 자신(observer)이 전달된다.

 

entreis[0]의 출력 결과

 

  • entries에는 observe를 통해 관찰 대상으로 등록된 요소들만 포함된다.
  • entries관찰 중인 요소에 대한 상태 정보를 담은 IntersectionObserverEntry 배열이다.
    • target: 관찰 중인 DOM 요소(예: trigger.current).
    • isIntersection: 해당 요소가 뷰포트와 교차(intersecting) 중인지 여부를 나타내는 boolean 타입 값
    • intersectionRatio: 요소의 가시 비율 (0.0 ~ 1.0)
    • boundingClientRect: 관찰 중인 요소의 크기와 위치
    • rootBounds: 뷰포트나 루트 요소의 크기와 위치
  • options
    • root: 관찰 기준이 될 요소(기본값: 뷰포트)
    • rootMargin: 관찰 기준 영역의 마진
    • threshold: 요소의 가시 비율

 

예를 들어 threshold: 1.0으로 options을 설정할 경우, 요소가 완전히 화면에 들어올 경우 IntersectionObserverEntry의 isIntersecting는 true가 된다.

  • threshold: 1.0 → 요소가 100% 화면에 들어와야 isIntersecting: true.
  • threshold: 0.5 → 요소가 절반만 화면에 보여도 isIntersecting: true.

 

3. 구현 로직

const [page, setPage] = useState(0);

const trigger = useRef<HTMLSpanElement>(null);

const onLoadMoreClick = async () => {
  setIsLoading(true);

  const newProducts = await getMoreProducts(page + 1);

  if (newProducts.length !== 0) {
    setProducts((prev) => [...prev, ...newProducts]);
    setPage((prev) => prev + 1);
  } else {
    setIsLastPage(true);
  }

  setIsLoading(false);
};

useEffect(() => {
  const observer = new IntersectionObserver(
    async (
      entries: IntersectionObserverEntry[],
      observer: IntersectionObserver
    ) => {
      console.log(entries);
      const element = entries[0];

      if (element.isIntersecting && trigger.current) {
        observer.unobserve(trigger.current);

        await onLoadMoreClick();
      }
    },
    { threshold: 1.0 }
  );

  if (trigger.current) {
    observer.observe(trigger.current);
  }

  return () => {
    observer.disconnect();
  };
}, [page]);

 

 

  1. 초기 설정
    • trigger 요소를 IntersectionObserver로 관찰 시작
    • threshold: 1.0 조건을 충족(요소가 100% 뷰포트에 노출)하면 콜백 실행.
  2. 요소 감지
    • entries[0].isIntersecting가 true이면:
      • 관찰 중단: observer.unobserve(trigger.current)
      • 데이터 로드: await onLoadMoreClick()
  3. 추가 로드
    • 데이터가 로드되면 page가 업데이트되고, useEffect 재실행.
    • IntersectionObserver는 새 trigger 요소를 다시 관찰.
  4. 클린업
    • useEffect 실행 전 기존 관찰자 정리: observer.disconnect()
    • 메모리 누수를 방지하고, 새로운 관찰자를 생성하기 위한 부분

 


참고 문서

 

IntersectionObserver - Web API | MDN

Intersection Observer API의 IntersectionObserver 인터페이스는 대상 요소와 상위 요소, 또는 대상 요소와 최상위 문서의 뷰포트가 서로 교차하는 영역이 달라지는 경우 이를 비동기적으로 감지할 수 있는

developer.mozilla.org

 

Intersection Observer API - Web API | MDN

Intersection Observer API는 상위 요소 또는 최상위 문서의 viewport와 대상 요소 사이의 변화를 비동기적으로 관찰할 수 있는 수단을 제공합니다.

developer.mozilla.org

 

 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/05   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
글 보관함