我的网站太重了,因为它从服务器(Google的Firebase Firestore)获取数据后会下载200-400张图片。
我想出了两种解决方案,希望有人回答其中一种:
function sample() {}{
const [items, setItems] = useState([])
const [imgLoading, setImgLoading] = useState(true) // imgLoading might have to be boolean[]
useEffect(() => {
axios.get(url).
.then(response => setItems(response.data))
}, [])
return (
items.map(item => <img src={item.imageUrl} onLoad={setImgLoading(false)} />)
)
}
答案 0 :(得分:1)
有用于此的库,但是如果您想自己滚动,可以使用IntersectionObserver
,如下所示:
const { useState, useRef, useEffect } = React;
const LazyImage = (imageProps) => {
const [shouldLoad, setShouldLoad] = useState(false);
const placeholderRef = useRef(null);
useEffect(() => {
if (!shouldLoad && placeholderRef.current) {
const observer = new IntersectionObserver(([{ intersectionRatio }]) => {
if (intersectionRatio > 0) {
setShouldLoad(true);
}
});
observer.observe(placeholderRef.current);
return () => observer.disconnect();
}
}, [shouldLoad, placeholderRef]);
return (shouldLoad
? <img {...imageProps}/>
: <div className="img-placeholder" ref={placeholderRef}/>
);
};
ReactDOM.render(
<div className="scroll-list">
<LazyImage src='https://i.insider.com/536a52d9ecad042e1fb1a778?width=1100&format=jpeg&auto=webp'/>
<LazyImage src='https://www.denofgeek.com/wp-content/uploads/2019/12/power-rangers-beast-morphers-season-2-scaled.jpg?fit=2560%2C1440'/>
<LazyImage src='https://i1.wp.com/www.theilluminerdi.com/wp-content/uploads/2020/02/mighty-morphin-power-rangers-reunion.jpg?resize=1200%2C640&ssl=1'/>
<LazyImage src='https://m.media-amazon.com/images/M/MV5BNTFiODY1NDItODc1Zi00MjE2LTk0MzQtNjExY2I1NTU3MzdiXkEyXkFqcGdeQXVyNzU1NzE3NTg@._V1_CR0,45,480,270_AL_UX477_CR0,0,477,268_AL_.jpg'/>
</div>,
document.getElementById('app')
);
.scroll-list > * {
margin-top: 400px;
}
.img-placeholder {
content: 'Placeholder!';
width: 400px;
height: 300px;
border: 1px solid black;
background-color: silver;
}
<div id="app"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.1/umd/react-dom.production.min.js"></script>
此代码是在屏幕上显示占位符后立即加载它们,但是如果您想要更大的检测余量,则可以调整IntersectionObserver
的{{3}}选项,使其开始加载同时仍然略微不在屏幕上。
答案 1 :(得分:1)
我将创建一个Image
组件来处理其自身的相关状态。然后在该组件内部,我将使用IntersectionObserver
API来判断图像的容器在用户浏览器中是否可见。
我将拥有isLoading
和isInview
状态,isLoading
将一直为true
,直到isInview
更新为true
。
当isLoading
为true
时,我将null
用作图像的src
,并显示占位符。
当容器在用户浏览器上可见时,仅加载src
。
function Image({ src }) {
const [isLoading, setIsLoading] = useState(true);
const [isInView, setIsInView] = useState(false);
const root = useRef(); // the container
useEffect(() => {
// sets `isInView` to true until root is visible on users browser
const observer = new IntersectionObserver(onIntersection, { threshold: 0 });
observer.observe(root.current);
function onIntersection(entries) {
const { isIntersecting } = entries[0];
if (isIntersecting) { // is in view
observer.disconnect();
}
setIsInView(isIntersecting);
}
}, []);
function onLoad() {
setIsLoading((prev) => !prev);
}
return (
<div
ref={root}
className={`imgWrapper` + (isLoading ? " imgWrapper--isLoading" : "")}
>
<div className="imgLoader" />
<img className="img" src={isInView ? src : null} alt="" onLoad={onLoad} />
</div>
);
}
我还将具有CSS样式,这些样式将切换占位符和图像的display
属性。
.App {
--image-height: 150px;
--image-width: var(--image-height);
}
.imgWrapper {
margin-bottom: 10px;
}
.img {
height: var(--image-height);
width: var(--image-width);
}
.imgLoader {
height: 150px;
width: 150px;
background-color: red;
}
/* container is loading, hide the img */
.imgWrapper--isLoading .img {
display: none;
}
/* container not loading, display img */
.imgWrapper:not(.imgWrapper--isLoading) .img {
display: block;
}
/* container not loading, hide placeholder */
.imgWrapper:not(.imgWrapper--isLoading) .imgLoader {
display: none;
}
现在,我的父组件将对所有图像网址发出请求。它还具有自己的isLoading
状态,即在设置true
时将显示其自己的占位符。当图片网址的请求解决后,我将在每个网址上进行映射以呈现我的Image
组件。
export default function App() {
const [imageUrls, setImageUrls] = useState([]);
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
fetchImages().then((response) => {
setImageUrls(response);
setIsLoading((prev) => !prev);
});
}, []);
const images = imageUrls.map((url, index) => <Image key={index} src={url} />);
return <div className="App">{isLoading ? "Please wait..." : images}</div>;
}
答案 2 :(得分:0)
将响应数据映射到“ isLoading”布尔数组,并更新回调以获取索引并更新特定的“ isLoading”布尔值。
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js" integrity="sha384-9/reFTGAW83EW2RDu2S0VKaIzap3H66lZH81PoYlFhbGU+6BZp6G7niu735Sk7lN" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js" integrity="sha384-B4gt1jrGC7Jh4AgTPSdUtOBvfO8shuf57BaghqFfPlYxofvL8/KUEfYiJOMMV+rV" crossorigin="anonymous"></script>