Lazy-loading image
Renders an image that supports lazy loading.
- Use the
useState()
hook to create a stateful value that indicates if the image has been loaded. - Use the
useEffect()
hook to check if theHTMLImageElement.prototype
contains'loading'
, effectively checking if lazy loading is supported natively. If not, create a newIntersectionObserver
and useIntersectionObserver.observer()
to observer the<img>
element. Use thereturn
value of the hook to clean up when the component unmounts. - Use the
useCallback()
hook to memoize a callback function for theIntersectionObserver
. This callback will update theisLoaded
state variable and useIntersectionObserver.disconnect()
to disconnect theIntersectionObserver
instance. - Use the
useRef()
hook to create two refs. One will hold the<img>
element and the other theIntersectionObserver
instance, if necessary. - Finally, render the
<img>
element with the given attributes. Applyloading='lazy'
to make it load lazily, if necessary. UseisLoaded
to determine the value of thesrc
attribute.
const LazyLoadImage = ({ alt, src, className, loadInitially = false, observerOptions = { root: null, rootMargin: '200px 0px' }, ...props }) => { const observerRef = React.useRef(null); const imgRef = React.useRef(null); const [isLoaded, setIsLoaded] = React.useState(loadInitially); const observerCallback = React.useCallback( entries => { if (entries[0].isIntersecting) { observerRef.current.disconnect(); setIsLoaded(true); } }, [observerRef] ); React.useEffect(() => { if (loadInitially) return; if ('loading' in HTMLImageElement.prototype) { setIsLoaded(true); return; } observerRef.current = new IntersectionObserver( observerCallback, observerOptions ); observerRef.current.observe(imgRef.current); return () => { observerRef.current.disconnect(); }; }, []); return ( <img alt={alt} src={isLoaded ? src : ''} ref={imgRef} className={className} loading={loadInitially ? undefined : 'lazy'} {...props} /> ); }; ReactDOM.createRoot(document.getElementById('root')).render( <LazyLoadImage src="https://picsum.photos/id/1080/600/600" alt="Strawberries" /> );