Introduction
In this lab, we will explore how to implement lazy loading images in a React application. Lazy loading improves page performance by delaying the loading of images until they are needed, reducing the initial load time and improving the user experience. We will use the Intersection Observer API and React hooks to create a reusable component that supports lazy loading images.
Lazy-Loading Image
index.htmlandscript.jshave already been provided in the VM. In general, you only need to add code toscript.jsandstyle.css.
To render an image that supports lazy loading, follow these steps:
- 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.prototypecontains'loading'. This checks if lazy loading is supported natively. If not, create a newIntersectionObserverand useIntersectionObserver.observer()to observe the<img>element. Use thereturnvalue 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 theisLoadedstate variable and useIntersectionObserver.disconnect()to disconnect theIntersectionObserverinstance. - Use the
useRef()hook to create two refs. One will hold the<img>element and the other theIntersectionObserverinstance, if necessary. - Finally, render the
<img>element with the given attributes. Applyloading='lazy'to make it load lazily, if necessary. UseisLoadedto determine the value of thesrcattribute.
Here's an example implementation of these steps:
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}
/>
);
};
To use this LazyLoadImage component, simply call it with the src and alt attributes of the image:
ReactDOM.createRoot(document.getElementById("root")).render(
<LazyLoadImage
src="https://picsum.photos/id/1080/600/600"
alt="Strawberries"
/>
);
Please click on 'Go Live' in the bottom right corner to run the web service on port 8080. Then, you can refresh the Web 8080 Tab to preview the web page.
Summary
Congratulations! You have completed the Lazy-Loading Image lab. You can practice more labs in LabEx to improve your skills.