懒加载图片
渲染一个支持懒加载的图片。
- 使用
useState()
钩子创建一个有状态的值,表示图片是否已加载。 - 使用
useEffect()
钩子检查HTMLImageElement.prototype
是否包含'loading'
,从而检查原生是否支持懒加载。如果不支持,创建一个新的IntersectionObserver
并使用IntersectionObserver.observer()
观察<img>
元素。使用钩子的返回值在组件卸载时进行清理。 - 使用
useCallback()
钩子来记忆一个回调函数,用于IntersectionObserver
。这个回调函数将更新isLoaded
状态变量,并使用IntersectionObserver.disconnect()
断开IntersectionObserver
实例。 - 使用
useRef()
钩子创建两个引用。一个引用将保存<img>
元素,另一个引用将保存IntersectionObserver
实例(如果需要)。 - 最后,使用给定的属性渲染
<img>
元素。如果需要,应用loading='lazy'
进行懒加载。使用isLoaded
来确定src
属性的值。
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="草莓"
/>
);