반응형
모든 리소스를 한 번에 로드하는 것이 아니라 사용자가 보는 뷰포트 영역에 접근했을 때 지연로딩하고 싶을 때가 있다.
그 때 사용할 수 있는 API 가 IntersectionObserver API 이다. 뷰포트 영역의 특정 교차점 부분을 진입했을 때 새로운 액션을 할 수 있다.
IntersectionObserver() - Web API | MDN (mozilla.org)
IntersectionObserver() - Web API | MDN
IntersectionObserver() 생성자는 새로운 IntersectionObserver 객체를 생성하고 반환합니다.
developer.mozilla.org
InsersectionObserver 생성자를 살펴보면 첫 번째 인자에는 두 번째 인자(대상 요소의 가시성 비율) 값보다 역치 값이 넘어갈 경우 감시할 옵저버 함수를 만들 수 있다.
특정 비율이 넘어갈 때 사진을 로드하는 함수를 만든다고 생각해보자.
감시할 imageRef 대상이 있는데 imageSrc 이미지 경로가 없다면, 그 때 생성자를 생성하여 감시를 시작한다.
감시하다가 교차지점에 도달하면 imageSrc 이미지 경로를 세팅한다.
import { useState, useRef, useEffect } from "react";
export function useLazyImageObserver({ src }) {
const [imageSrc, setImageSrc] = useState(null);
const imageRef = useRef(null);
useEffect(()=>{
let observer;
if (imageRef && !imageSrc) {
observer = new IntersectionObserver(([entry]) => {
if (entry.isIntersecting) {
setImageSrc(src);
observer.unobserve(imageRef.current);
}
}, { threshold: [0.25] });
observer.observe(imageRef.current);
}
return () => {
observer && observer.disconnect(imageRef);
};
}, [imageRef, imageSrc, src]);
return { imageSrc, imageRef };
}
[사용부]
import { memo } from "react";
import { useLazyImageObserver } from "../hooks/useLazyImageObserver";
export const LazyImage = memo(({src, alt})=>{
const { imageSrc, imageRef } = useLazyImageObserver({ src });
return (
<img ref={imageRef} src={imageSrc} alt={alt} width='200px' height='300px'/>
);
});
const urlList = [
'https://picsum.photos/200/300?random=1',
'https://picsum.photos/200/300?random=2',
'https://picsum.photos/200/300?random=3',
'https://picsum.photos/200/300?random=4',
'https://picsum.photos/200/300?random=5',
'https://picsum.photos/200/300?random=6',
'https://picsum.photos/200/300?random=7',
'https://picsum.photos/200/300?random=8',
'https://picsum.photos/200/300?random=9',
'https://picsum.photos/200/300?random=10',
'https://picsum.photos/200/300?random=11',
'https://picsum.photos/200/300?random=12',
'https://picsum.photos/200/300?random=13',
'https://picsum.photos/200/300?random=14',
'https://picsum.photos/200/300?random=15',
'https://picsum.photos/200/300?random=16',
'https://picsum.photos/200/300?random=17',
'https://picsum.photos/200/300?random=18',
'https://picsum.photos/200/300?random=19',
'https://picsum.photos/200/300?random=20',
'https://picsum.photos/200/300?random=21',
'https://picsum.photos/200/300?random=22',
'https://picsum.photos/200/300?random=23',
'https://picsum.photos/200/300?random=24',
'https://picsum.photos/200/300?random=25',
'https://picsum.photos/200/300?random=26',
'https://picsum.photos/200/300?random=27',
'https://picsum.photos/200/300?random=28',
'https://picsum.photos/200/300?random=29',
'https://picsum.photos/200/300?random=30',
'https://picsum.photos/200/300?random=31',
'https://picsum.photos/200/300?random=32',
'https://picsum.photos/200/300?random=33',
'https://picsum.photos/200/300?random=34',
'https://picsum.photos/200/300?random=35',
'https://picsum.photos/200/300?random=36',
];
function App() {
return (
<div style={{ width: '600px' }}>
{urlList && urlList.map((url, index) => (
<LazyImage key={index} src={url} alt=""/>
))}
</div>
);
}
반응형
'언어 > React' 카테고리의 다른 글
[React] Hook 은 사실 Closure 이다. (1) | 2023.10.16 |
---|---|
[React] debounce 최적화 (0) | 2023.10.15 |
[React] Suspense 와 React-Query 사용 시 주의사항 (0) | 2023.01.01 |
[React] Hook 사용 시 유의사항 (0) | 2022.12.30 |