[React.js] Lazy Image Component
2021. 12. 15. 22:56ㆍReactJS/Information
React.js에서 Lazy Image Loading을 구현하기 위한 방법이다.
해당 Component를 사용하게 되면 Lazy Image Loading을 구현할 수 있다.
먼저 코드를 보면서 설명해보도록 하겠다.
import React, {useEffect, useRef, useState} from 'react';
interface ILazyImageProps {
imgSrc: string;
className?: string;
alt?: string;
}
let observer: IntersectionObserver | null = null;
const __LOAD_IMAGE__ = "loadImage";
function onIntersection(
entries: IntersectionObserverEntry[],
io: IntersectionObserver
) {
entries.forEach(entry => {
if (entry.isIntersecting) {
io.unobserve(entry.target);
entry.target.dispatchEvent(new CustomEvent(__LOAD_IMAGE__));
}
});
}
function LazyImage({imgSrc, className, alt}: ILazyImageProps) {
const imgRef = useRef<HTMLImageElement>(null);
const [imgLoad, setImgLoad] = useState(false);
useEffect(() => {
const imgEl = imgRef.current;
imgEl && imgEl.addEventListener(__LOAD_IMAGE__, () => {setImgLoad(true)});
return () => {
imgEl && imgEl.removeEventListener(__LOAD_IMAGE__, () => {setImgLoad(true)});
};
}, []);
useEffect(() => {
if (!observer) {
observer = new IntersectionObserver(onIntersection, {
threshold: 0.5
});
}
imgRef.current && observer.observe(imgRef.current);
}, []);
return (<img alt={alt} className={className !== undefined ? className : imgSrc} ref={imgRef} src={imgLoad ? imgSrc ? imgSrc : NoImage : NoImage}/>);
}
export default React.memo(LazyImage)
해당 컴포넌트의 Props로 src(이미지 주소), className(밖에서 Style을 쓸 경우에 대한 대비)를 줬다.
onIntersection 함수의 역할 ?
- IntersectionObserverEntry에 대해 관찰을 해제하고, entry에 대해 "loadImage" 라는 사용자 이벤트를 발생시킨다.
IntersectionObserverEntry는 어떻게 들어오는가 ?
- new IntersectionObserver()에 callback 함수 안에 들어있다.
컴포넌트 생성시
- useRef hook을 이용해 img를 등록하고, 이 img에 , "loadImage" 라는 event가 발생 될 경우 state를 변경시켜 Re rendering 시킨다.
- 여기서 cleanup(ComponentDidUnmount - useEffect 내 return 함수) 함수로 해당 Component가 Unmount 될 경우 img에 등록되어 있는 이벤트를 삭제한다.(1번작업 삭제)
- observer(관찰자)가 null일 경우(초기 로딩된 상태 일 경우) observer를 등록하고, imgRef를 관찰한다.
- 만약 0.5(50%) 만큼 img가 보이게 됐다면(로딩이 안된 상태에서의 50%를 뜻함.) onIntersection 함수가 발동되면서 "loadImage" 라는 evnet를 발생하게 된다.(위 역할 참고)
(만약 50%가 안됐다면 NoImage를 보여주게 되는데 해당 부분은 따로 Image가 없을 때 보여줄 Image를 import 하면 된다.) - 그렇게 되면 onIntersection 함수에 의해 observer가 해제되게 되고, 이미지 로딩이 끝난다.
그리고 해당 컴포넌트는 React.memo로 src나 className이 바뀌었을 때만 Re rendering하게 설정해주어 렌더링 최적화를 진행한다.
IntersectionObserver는 그 외에도 Infinite Scroll을 구현하거나 할 때 자주 쓰인다.
'ReactJS > Information' 카테고리의 다른 글
[React.js] React-Testing-Library 사용하기 (0) | 2022.01.03 |
---|---|
[React.js] GraphQL 서버와 통신하기 (0) | 2021.12.21 |
[React.js] React Query(useQuery, useMutation) (0) | 2021.12.14 |
[React.js] createPortal 사용하여 DOM을 원하는 요소 안으로 옮기 (0) | 2021.12.11 |
[React.js] 최상위 API React.memo (0) | 2021.12.11 |