我的网站太重了,因为它在从服务器(Google 的 Firebase Firestore)获取数据后下载了 200-400 张图像。
我想出了两个解决方案,我希望有人能回答其中一个:
- 我想将每个 img 设置为具有加载状态,并使访问者能够在加载之前看到占位符图像。因为我不知道从服务器获取数据之前我得到了多少图像,所以我发现很难通过 useState 初始化图像加载状态。这可能吗?那么,如何?
- 如何延迟加载图片?图像使用占位符进行初始化。当滚动条靠近图像时,图像开始下载并替换占位符。
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)} />)
)
}
最佳答案
我会创建一个 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;
}
现在我的父组件将执行对所有图像 url 的请求。它还会有自己的 isLoading
状态,当设置为 true
时,它会显示自己的占位符。当图像 url 的请求得到解决时,我将映射到每个 url 以呈现我的 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>;
}
关于javascript - react : How do you lazyload image from API response?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63405009/