ReactでHooksとIntersection Observer API使って、プレースホルダー付きで画像の遅延読み込みするコンポーネントをだいぶ前に作った時のメモ。
使い方<LazyImagesrc="https://your-image-url"/>
importReact,{useState,useRef,useEffect}from'react'importPropTypesfrom'prop-types'importstyledfrom'styled-components'require('intersection-observer')// intersection-observer api polyfillconstImg=styled.img`
transition: all 1s ease-in-out;
@keyframes placeHolder {
0% {
background-position: -468px 0;
}
100% {
background-position: 468px 0;
}
}
${props=>props.imageLoaded||props.noPlaceholder||`
animation-name: placeHolder;
animation-duration: 1.5s;
animation-fill-mode: forwards;
animation-iteration-count: infinite;
animation-timing-function: linear;
background: #f6f7f8;
background: linear-gradient(to right, #eeeeee 8%, #dfdfdf 20%, #eeeeee 33%);
background-size: 800px 104px;
filter: blur(5px);
position: relative;
`}
`functionLazyImage({src,...props}){constimageRef=useRef()const[imageLoaded,setImageLoaded]=useState(false)letobserveruseEffect(()=>{observer=newIntersectionObserver(startLoading,{rootMargin:'50px'})if(!imageLoaded){observer.observe(imageRef.current)}return()=>observer.unobserve(imageRef.current)},[])functionstartLoading(entries,object){entries.forEach((entry)=>{if(!entry.isIntersecting)returnif(entry.intersectionRatio>0){observer.unobserve(entry.target)}if(!imageLoaded){constdownloadingImage=newImage()downloadingImage.onload=()=>{if(imageRef.current){imageRef.current.setAttribute('src',downloadingImage.src)setImageLoaded(true)}}downloadingImage.src=srcobject.unobserve(entry.target)}object.unobserve(entry.target)})}return(<Img{...props}alt="GOOD BOYE"ref={imageRef}imageLoaded={imageLoaded}/>
)}LazyImage.propTypes={src:PropTypes.string,noPlaceholder:PropTypes.bool,}LazyImage.defaultProps={src:'',noPlaceholder:false,}exportdefaultLazyImage