웹 페이지 성능 개선을 위해 가장 효과적인 방법 중 하나는 이미지 Lazy Loading이다.
사용자가 당장 보지 않는 이미지는 로딩하지 않음으로써 페이지 초기 로딩 속도를 크게 개선할 수 있다.
방법은 여러 가지가 있지만, IntersectionObserver API를 활용해 React에서 Lazy Loading을 구현해보았다.
Lazy Loading(지연 로딩)은 페이지가 처음 로드될 때 모든 리소스를 한 번에 불러오는 것이 아니라, 사용자가 필요로 할 때 불러오는 방식
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 등을 통해 상태 확인
});
};
entriesobserverimport 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;
imgRef를 통해 이미지 DOM 요소에 접근한다.IntersectionObserver는 이미지 요소가 뷰포트에 들어올 때를 감지한다.entry.isIntersecting이 true인 경우에만 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안에 작성해주면 끝