---
title: Lazy-loading image
type: snippet
tags: [components,effect,state]
cover: strawberries
author: chalarangelo
dateModified: 2022-07-29T05:00:00-04:00
---
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 the `HTMLImageElement.prototype` contains `'loading'`, effectively checking if lazy loading is supported natively. If not, create a new `IntersectionObserver` and use `IntersectionObserver.observer()` to observer the `
` element. Use the `return` value of the hook to clean up when the component unmounts.
- Use the `useCallback()` hook to memoize a callback function for the `IntersectionObserver`. This callback will update the `isLoaded` state variable and use `IntersectionObserver.disconnect()` to disconnect the `IntersectionObserver` instance.
- Use the `useRef()` hook to create two refs. One will hold the `
` element and the other the `IntersectionObserver` instance, if necessary.
- Finally, render the `
` element with the given attributes. Apply `loading='lazy'` to make it load lazily, if necessary. Use `isLoaded` to determine the value of the `src` attribute.
```jsx
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 (
);
};
```
```jsx
ReactDOM.createRoot(document.getElementById('root')).render(
);
```