IntersectionObserver로 이미지 Lazy Loading

rloo8·2025년 7월 27일

웹 페이지 성능 개선을 위해 가장 효과적인 방법 중 하나는 이미지 Lazy Loading이다.
사용자가 당장 보지 않는 이미지는 로딩하지 않음으로써 페이지 초기 로딩 속도를 크게 개선할 수 있다.
방법은 여러 가지가 있지만, IntersectionObserver API를 활용해 React에서 Lazy Loading을 구현해보았다.


💡 Lazy Loading이란?

Lazy Loading(지연 로딩)은 페이지가 처음 로드될 때 모든 리소스를 한 번에 불러오는 것이 아니라, 사용자가 필요로 할 때 불러오는 방식


🔧 구현 방법

1. IntersectionObserver란?

https://developer.mozilla.org/ko/docs/Web/API/IntersectionObserver

IntersectionObserver는 특정 요소가 뷰포트에 들어오는지를 감지할 수 있는 웹 API이다.
이미지가 화면에 보일 때만 src를 설정해 로딩을 시작하는 방식으로 Lazy Loading을 구현할 수 있다.

const observer = new IntersectionObserver(callback, options);

두 개의 인자를 받는다:
1. callback: 관찰 대상의 상태가 바뀔 때 실행되는 함수
2. options: 관찰 방식 설정 (뷰포트 기준, 여유 margin, 감지 기준 등)


콜백 함수는 다음과 같은 형태로 정의한다:
const callback = (entries, observer) => {
  entries.forEach((entry) => {
    // entry.isIntersecting 등을 통해 상태 확인
  });
};
  1. entries
    entries는 IntersectionObserverEntry 객체들의 배열
    각각의 entry는 개별 관찰 대상 요소의 상태 정보를 담고 있다.
  • 주요 속성:
    • entry.target: 감지 중인 요소 (imgRef.current 등)
    • entry.isIntersecting: 요소가 현재 뷰포트에 들어와 있는지 여부 (true 또는 false)
    • entry.intersectionRatio: 뷰포트와 얼마나 겹치는지 (0.0 ~ 1.0)
  1. observer
    observer는 현재 생성한 IntersectionObserver 인스턴스 자체

2. 예시 코드

import React, { useEffect, useRef } from "react";

function Img(props) {
  const imgRef = useRef(null);

  useEffect(() => {
    const callback = (entries) => {
      entries.forEach((entry) => {
        if (entry.isIntersecting) {
          entry.target.src = entry.target.dataset.src;
          observer.unobserve(entry.target);
        }
      });
    };

    const observer = new IntersectionObserver(callback, {});
    observer.observe(imgRef.current);
  }, []);

  return (
    <div>
      <img data-src={props.image} ref={imgRef} />
    </div>
  );
}

export default Img;

3. 작동 원리

  • imgRef를 통해 이미지 DOM 요소에 접근한다.
  • IntersectionObserver는 이미지 요소가 뷰포트에 들어올 때를 감지한다.
  • 이때 entry.isIntersectingtrue인 경우에만 data-src 값을 src에 할당해 이미지를 로딩한다.
  • 이미지를 로드한 후에는 observer.unobserve()로 해당 요소에 대한 관찰을 해제한다.

※ 참고로 IntersectionObserver는 기본적으로 세 가지 상황에서 콜백을 실행한다:
1. 최초 실행 시
2. 타겟이 뷰포트에 진입할 때
3. 타겟이 뷰포트에서 벗어날 때

불필요한 실행을 막기 위해 entry.isIntersecting 조건문을 반드시 사용하는 것이 중요하다.


➕간단하게 구현하기 위해 react-lazyload 라이브러리를 사용할 수도 있다.
https://www.npmjs.com/package/react-lazyload

import React, { useEffect, useRef } from "react";
import LazyLoad from 'react-lazyload';

function Img(props) {
  return (
    // offset: 얼마나 미리 불러올지(스크롤 위치)
    <LazyLoad offset={500}>
      <img src={props.image}  />
    </LazyLoad>
  );
}

export default Img;

Lazy loading을 적용시킬 요소를 LazyLoad안에 작성해주면 끝

0개의 댓글