Skip to content

Instantly share code, notes, and snippets.

@nihlton
Last active December 28, 2020 10:26
Show Gist options
  • Save nihlton/b3939a63b7c02a3374154fe258ecaef1 to your computer and use it in GitHub Desktop.
Save nihlton/b3939a63b7c02a3374154fe258ecaef1 to your computer and use it in GitHub Desktop.
Minimal Lazy Loading Image Component
import React, { useEffect, useRef, useState } from 'react'
import './LazyImage.scss'
const LazyImage = (props) => {
const [ isLoaded, setIsLoaded ] = useState(false)
const [ isVisible, setIsVisible ] = useState(false)
const { src, alt, width, height, className } = props
const placeHolderStyle = {paddingBottom: `${(height / width) * 100}%`}
const imageRef = useRef()
useEffect(() => {
const handleVisibility = (entries) => {
if (entries[0].intersectionRatio > 0 || entries[0].isIntersecting) {
setIsVisible(true)
visibilityObserver.disconnect()
}
}
const visibilityObserver = new IntersectionObserver(handleVisibility)
visibilityObserver.observe(imageRef.current)
return () => visibilityObserver.disconnect()
}, [ imageRef, setIsVisible ])
const handleLoad = () => setIsLoaded(true)
return <div className={`lazy-image ${isLoaded ? '' : 'loading'} ${className || ''}` } ref={imageRef}>
{isVisible && <img onLoad={handleLoad} onError={handleLoad} src={src} alt={alt}/>}
<div className='flow-holder' style={placeHolderStyle}/>
</div>
}
export default LazyImage
.lazy-image {
position: relative;
transition: opacity .5s ease-in-out;
&.loading { opacity: 0; }
.flow-holder { display: block; }
img {
position: absolute;
top: 0;
left: 0;
height: 100%;
width: 100%;
object-fit: contain;
}
}
@nihlton
Copy link
Author

nihlton commented Apr 21, 2020

Was looking at existing components. 100k? seems a bit much.

this'll do.

Not compatible with IE11 or less >> https://caniuse.com/#feat=intersectionobserver

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment