이미지를 빠르게 다운하는것은 영상이 어쨌든 영상 다운이 후순위가 되기에 2번 방안 선택.
Intersection Observer를 사용해 특정 엘리먼트가 화면에 들어오는것을 감지하여 해당 이미지들이 화면에 나오면 이미지를 다운로드 하도록 설정. 브라우저가 제공하는 기능이기에 성능의 이득을 얻을 수 있음
const imgRef = useRef()
useEffect(() => {
const options = {};
const callback = (entries, observer) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
entry.target.src = entry.target.dataset.src;
observer.unobserve(entry.target);
}
});
};
const observer = new IntersectionObserver(callback, options);
observer.observe(imgRef.current);
}, []);
<img data-src={props.img} ref={imgRef} />
한번만 실행시키기위해 useEffect에 빈 dependency로 구현하였고
observer 또한 한번만 관찰하도록 한번 실행이 된 이후에 observer.unobserve(target)
을 입력하여 관찰을 그만두게 해주었다. 또한 entry.isIntersecting
으로 화면에 노출 여부를 확인하는 조건을 줌으로써, 이 이미지가 브라우저내에 표시가 될때를 감지하였다.
또한 리액트에서 DOM을 직접 조작하기 위해 useRef를 사용하였다.
webp 지원 안되는 브라우저도 있으므로 picture
를 이용하여 처리해줘야한다. picture
tag는 타입뿐 아니라 브라우저 크기 등 다른것으로도 조건을 줄수 있으므로 picture 자세히 알아보기 여기서 자세히 읽어보도록하자.
webp를 먼저 불러오고 이를 지원하지 않는 브라우저면 아래 img태그로 jpg 파일을 불러오도록 한다.
<picture>
<source data-srcset={webpImg} type="image/webp"/>
<img src={jpgImg} />
</picture>
if (entry.isIntersecting) {
entry.target.src = entry.target.dataset.src;
entry.target.previousSibling.srcset= entry.taget.previousSibling.dataset.srcset;
observer.unobserve(entry.target);
}
webp를 먼저 불러오고 이를 지원하지 않는 브라우저면 아래 img태그를 이용함
useEffect에 source도 lazy loading을 처리해주기 위해 entry.trget.previousSibling.srcset
코드 추가