JavaScript / React - IntersectionObserver

반응형

IntersectionObserver는 웹 개발에서 아주 유용한 API 이다.

이 API는 특정 요소(target)가 뷰포트나 지정한 컨테이너와 교차하는 정도를

비동기적으로 감지할 수 있게  해준다.

즉 스크롤할 때 요소가 화면에 나타나거나 사라지는 시점을 효율적으로 파악할 수 있도록 해준다.

IntersectionObserver를 사용하는 이유

  1. 성능 최적화
    - 스크롤 이벤트를 직접 감시하는 방식은 매번 스크롤 이벤트가 발생할때마다
    많은 연산을 해야하기 때문에 성능 이슈가 발생할 수 있다.
    IntersectionObsever는 브라우저가 최적화한 방식으로 감지하므로 성능 부담이 적다는 장점이 있다.
  2. 간편한 API
    - 요소가 화면에 들어왔는지 여부를 쉽게 감지할 수 있어, lazy loading (이미지나 리소스의 지연 로딩) 또는
    애니메이션 트리거 등에 유용하게 사용할 수 있다.

 

동작원리

  • 관찰 대상 설정 : 개발자는 감시하고 싶은 요소 (ex: img, section 등)를 선택한다.
  • 교차 상태 감지 : 브라우저는 이 요소가 뷰포트 또는 특정 부모 컨테이너와 얼마나 교차(intersect)하는지를 감지한다.
  • 비동기 콜백 (async & await callback) 실행 : 요소가 설정한 기준 (ex: 일정 비율 이상 보임) 에 도달하면
    미리 지정한 콜백 함수가 호출된다.
    이 콜백 함수에서는 요소가 보이기 시작했을 때 필요한 작업 (ex: animation 실행, lazy loading등)을 수행할 수 있다.

특정 스크롤 위치에 도달하면 등장할때 애니메이션 실행하는 예제

 

주요 옵션 및 속성

▼ threshold

  • 0부터 1사이의 숫자 또는 숫자 배열로, 요소가 어느 정도 보였을 때 콜백을 실행할지를 결정한다.
    예를 들어 threshold가 0.5라면, 해당 요소의 50% 이상이 뷰표트에 들어왔을 때 콜백 함수가 호출된다.

▼ root

  • 기본값은 브라우저의 뷰포트이다.
    만약 특정 컨테이너 내에서 교차 여부를 감지하고 싶다면, 해당 컨테이너 요소를 root로 지정할 수 있다.

▼ rootMargin

  • 뷰포트의 경계를 확장하거나 축소할 수 있는 마진을 설정한다.
    예를 들어 '0px 0px -100px 0px'와 같이 설정하면 뷰포트 하단에서 100px 만큼 여유를 두어
    그 영역에 들어올 때 콜백을 실행할 수 있다.
    이는 요소가 실제로 완전이 보이기 전에 미리 작업을 시작할 수 있게 도와준다.
// 사용 예제

{
  // thershold: 요소가 보이는 비율을 설정
  threshold: 0.5, // 이 값을 높이면 요소가 일정 비율 이상 보일 때까지 애니메이션이 실행되지 않음

  // rootMargin: 뷰포트 경계에 대해 추가적인 마진을 설정
  rootMargin: '0px 0px -100px 0px', // 음수 값을 늘리면 요소가 뷰포트에 들어오기 전에 애니메이션을 늦출 수 있음
}

 

 

IntersectionObserverEntry 객체

콜백 함수는 IntersectionObserver 객체를 배열 형태로 전달받는다.

이 객체에는 다음과 같은 중요한 속성들이 있다.

  • isIntersecting: 요소가 현재 교차 상태인지 (true/false)
  • intersectionRatio: 요소가 뷰포트와 얼마나 곂치는지를 나타내는 비율 (0~1)
  • target: 감시 중인 실제 DOM 요소
  • boundingClientRect, intersectionRect, rootBounds: 요소와 뷰포트의 위치와 크기에 대한 정보를 제공
// IntersectionObserver객체 및 옵션 사용 예제

import { useEffect, useRef } from 'react';

// useScrollReveal custom hook - 요소가 뷰포트에 일정 비율 이상이 보이면 'fade-in' 클래스를 추가.
const useScrollReveal = (threshold = 0.1) => {
  // threshold 매개변수는 기본값이 0.1 (요소가 10% 보이면 애니메이션 효과를 트리거)
  const elementRef = useRef(null); // 관찰할 요소에 대한 참조를 생성

  useEffect(() => {
    const element = elementRef.current; // 실제 DOM 요소에 접근
    if (!element) return; // 요소가 없으면 진행 X

    // IntersectionObserver 생성
    const observer = new IntersectionObserver(
      ([entry]) => {
        // entry.inIntersectiong이 true이면 요소가 뷰포트 내에 일정 비율 이상 보임
        if (entry.isIntersecting) {
          entry.target.classList.add('fade-in'); // fade-in 클래스 추가
          observer.unobserve(entry.target); // 한번 애니메이션이 실행되면 중지
        }
      },

      {
        // thershold: 요소가 보이는 비율을 설정
        threshold: 0.5, // 이 값을 높이면 요소가 일정 비율 이상 보일 때까지 애니메이션이 실행되지 않음

        // rootMargin: 뷰포트 경계에 대해 추가적인 마진을 설정
        rootMargin: '0px 0px -100px 0px', // 음수 값을 늘리면 요소가 뷰포트에 들어오기 전에 애니메이션을 늦출 수 있음
      }
    );

    observer.observe(element); // oberver를 이용해 실제 DOM 요소를 감시하기 시작.

    // 컴포넌트가 언마운트될 때 옵저버를 해제하여 메모리 누수 방지
    return () => observer.disconnect();
  }, [threshold]); // threshold 값이 변경되면 재실행
  // 관찰할 DOM 요소의 ref를 반환하고 이 ref를 각 컴포넌트의 ref 속성에 할당하면,
  // 해당 요소가 IntersectionObsever에 의해 감시됨.
  return elementRef;
};

export default useScrollReveal;

 

실무 적용

src/
├── components/
│   ├── OOO.jsx
├── hooks/
│   └── useScrollReveal.js
├── App.jsx
├── main.jsx
└── index.css

실제로 리액트 같은 프레임워크에서 IntersectionObserver를 사용할 때는

커스텀 훅 (useScrollReveal) 등을 만들어 각 컴포넌트에 쉽게 적용할 수 있다.

  • 각 섹션이나 컴포넌트의 초기 CSS 상태를 opacity-0 또는 transform translate-y-10과 같이 설정해두고
    InterSectionObserver가 감지되면 fade-in 클래스를 추가하여 애니메이션을 적용한다.
@tailwind base;
@tailwind components;
@tailwind utilities;

html {
  scroll-behavior: smooth;
}

body {
  font-family: 'Inter', sans-serif;
}

.dark {
  color-scheme: dark;
}

/* IntersectionObserver 초기 CSS 상태 - fade-in 클래스 적용*/

.fade-in { 
  opacity: 1 !important;
  transform: translateY(0) !important;
}
  • 이 방법으로 lazy loading, 애니메이션 트리거, 인피니트 스크롤등 다양한 기능을 손쉽게 구현할 수 있다.

이와 같이 IntersectionObserver는 웹 페이지의 성능 최적화와 사용자 경험 향상에 매우 유용한 도구이다.

실제 적용 시에는 프로젝트의 요구사항에 맞게 threshold, rootMargin등 옵션을 조절하여

최적의 타이밍에 원하는 효과를 낼 수 있도록 설정할 수 있다.

반응형

'React' 카테고리의 다른 글

React - useRef  (0) 2025.03.12
React- React에서 인라인 스타일 사용하기  (0) 2025.02.28
React - React의 렌더링 방식 : State  (0) 2025.02.27
React - State  (0) 2025.02.26
React - children props  (0) 2025.02.21