react如何解决图片懒加载
React 实现图片懒加载的方法
使用 Intersection Observer API
Intersection Observer 是浏览器原生 API,可高效检测元素是否进入视口。通过监听目标元素与视口的交叉状态,实现懒加载。
import { useEffect, useRef } from 'react';
const LazyImage = ({ src, alt }) => {
const imgRef = useRef(null);
useEffect(() => {
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = src;
observer.unobserve(img);
}
});
}, { threshold: 0.1 });
if (imgRef.current) observer.observe(imgRef.current);
return () => {
if (imgRef.current) observer.unobserve(imgRef.current);
};
}, [src]);
return <img ref={imgRef} alt={alt} />;
};
使用第三方库(如 react-lazy-load-image-component)
现成库封装了复杂逻辑,简化实现过程。例如 react-lazy-load-image-component 提供开箱即用的组件。
import { LazyLoadImage } from 'react-lazy-load-image-component';
import 'react-lazy-load-image-component/src/effects/blur.css';
const MyImage = () => (
<LazyLoadImage
src="image.jpg"
alt="Example"
effect="blur" // 可选加载效果
placeholderSrc="placeholder.jpg" // 占位图
/>
);
自定义滚动事件监听(兼容旧浏览器)
对于不支持 Intersection Observer 的环境,可通过监听滚动事件手动判断元素位置。
import { useEffect, useRef, useState } from 'react';
const LazyImage = ({ src, alt }) => {
const imgRef = useRef(null);
const [isLoaded, setIsLoaded] = useState(false);
const checkVisibility = () => {
if (imgRef.current && !isLoaded) {
const rect = imgRef.current.getBoundingClientRect();
if (rect.top < window.innerHeight && rect.bottom > 0) {
setIsLoaded(true);
}
}
};
useEffect(() => {
window.addEventListener('scroll', checkVisibility);
checkVisibility(); // 初始检查
return () => window.removeEventListener('scroll', checkVisibility);
}, []);
return <img ref={imgRef} src={isLoaded ? src : ''} alt={alt} />;
};
优化建议
添加占位符与加载状态
使用低分辨率占位图(LQIP)或纯色背景,避免布局偏移。CSS 可设置默认宽高比容器。
.lazy-image-container {
aspect-ratio: 16/9;
background-color: #f0f0f0;
}
性能注意事项
滚动事件监听需配合节流(throttle)或防抖(debounce)。Intersection Observer 是首选方案,性能更优且无需手动管理事件。
服务端渲染(SSR)兼容
在 Next.js 等框架中,可直接使用内置 next/image 组件,支持懒加载与自动优化。
import Image from 'next/image';
<Image src="/image.jpg" alt="Example" width={500} height={300} lazy />






