프론트엔드 개발자이며 페이지 성능에 관심이 있다면 화면에 보이지 않는 이미지를 레이지 로딩하기 위해 IntersectionObserver
을 사용해본 사람이 많을 것이다.
IntersectionObserver
는 브라우저의 빌트인 자바스크립트 API이며 상대적으로 최신 브라우저들에서만 지원Intersection을 이용한 이미지 레이지로더 커스텀 훅 예시 (이를 제공하는 외부 라이브러리가 있지만 직접 만들어서 사용해보는 것을 추천)
import { useEffect, useRef, useState } from 'react'
interface Params {
src: string
}
const useLazyImageObserver = ({ src }: Params) => {
const [imageSrc, setImageSrc] = useState<string | null>(null)
const imageRef = useRef<HTMLImageElement>(null)
useEffect(() => {
let observer: IntersectionObserver | null = null
if (imageRef && !imageSrc) {
observer = new IntersectionObserver(
([entry]) => {
if (entry.isIntersecting) {
setImageSrc(src)
observer!.unobserve(imageRef.current!)
}
},
{ threshold: [0.25] }
)
observer.observe(imageRef.current!)
}
}, [imageRef, imageSrc, src])
return { imageSrc, imageRef }
}
export default useLazyImageObserver
Can't find variable: IntersectionObserver
해당 에러가 일어나는 경우는 드물지만 배포 후 서비스를 운영할 때 경험을 했던 문제이다.
이 문제가 일어날 수 있는 경우:
IntersectionObserver
을 지원하지 않음IntrersectionObserver
은 브라우저 빌트인 API이기 때문에 Node환경에서 코드가 실행이 되었다면 지원이 되지 않음 (window
가 없는 경우)Fix:
import { useEffect, useRef, useState } from 'react'
interface Params {
src: string
}
const useLazyImageObserver = ({ src }: Params) => {
const [imageSrc, setImageSrc] = useState<string | null>(null)
const imageRef = useRef<HTMLImageElement>(null)
useEffect(() => {
let observer: IntersectionObserver | null = null
if (imageRef && !imageSrc && 'IntersectionObserver' in window) {
observer = new IntersectionObserver(
([entry]) => {
if (entry.isIntersecting) {
setImageSrc(src)
observer!.unobserve(imageRef.current!)
}
},
{ threshold: [0.25] }
)
observer.observe(imageRef.current!)
}
}, [imageRef, imageSrc, src])
return { imageSrc, imageRef }
}
export default useLazyImageObserver
'IntersectinObserver' in window
조건을 통해 IntersectionObserver
의 여부를 확인하고 있을 때 만 실행하는 방법으로 간단한 수정이 가능