Lazy-loading images in React
Lazy loading images is a great way to improve the performance of your web application. By only loading images when they are in the viewport, you can reduce the initial load time and save bandwidth. In React, you can create a custom component that supports lazy loading using the IntersectionObserver
API.
In order to implement the LazyLoadImage
component, you will need to use the useState()
hook to create a stateful value that indicates if the image has been loaded. You will also use the useEffect()
hook to check if the HTMLImageElement.prototype
contains 'loading'
, effectively checking if lazy loading is supported natively.
If not, you will create a new IntersectionObserver
and use IntersectionObserver.observer()
to observe the <img>
element. Finally, you will use the useRef()
hook to create two refs, one for the <img>
element and the other for the IntersectionObserver
instance, if necessary.
In order to render the <img>
element, you will apply the loading='lazy'
attribute to make it load lazily, if necessary. Use the isLoaded
state variable to determine the value of the src
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" /> );