React:你如何从 API 响应中延迟加载图像?

我的网站太重了,因为它在从服务器(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)} />)

  )

}


慕少森
浏览 118回答 3
3回答

斯蒂芬大帝

我会创建一个Image组件来处理它自己的相关状态。然后在这个组件内,我会使用IntersectionObserverAPI 来判断图像的容器在用户浏览器上是否可见。我会isLoading和isInview状态,isLoading将永远true直到isInview更新到true.而当isLoadingis时true,我会使用nullas 作为src图像并显示占位符。src仅在容器在用户浏览器上可见时加载。function Image({ src }) {&nbsp; const [isLoading, setIsLoading] = useState(true);&nbsp; const [isInView, setIsInView] = useState(false);&nbsp; const root = useRef(); // the container&nbsp; useEffect(() => {&nbsp; &nbsp; // sets `isInView` to true until root is visible on users browser&nbsp; &nbsp; const observer = new IntersectionObserver(onIntersection, { threshold: 0 });&nbsp; &nbsp; observer.observe(root.current);&nbsp; &nbsp; function onIntersection(entries) {&nbsp; &nbsp; &nbsp; const { isIntersecting } = entries[0];&nbsp; &nbsp; &nbsp; if (isIntersecting) { // is in view&nbsp; &nbsp; &nbsp; &nbsp; observer.disconnect();&nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; setIsInView(isIntersecting);&nbsp; &nbsp; }&nbsp; }, []);&nbsp; function onLoad() {&nbsp; &nbsp; setIsLoading((prev) => !prev);&nbsp; }&nbsp; return (&nbsp; &nbsp; <div&nbsp; &nbsp; &nbsp; ref={root}&nbsp; &nbsp; &nbsp; className={`imgWrapper` + (isLoading ? " imgWrapper--isLoading" : "")}&nbsp; &nbsp; >&nbsp; &nbsp; &nbsp; <div className="imgLoader" />&nbsp; &nbsp; &nbsp; <img className="img" src={isInView ? src : null} alt="" onLoad={onLoad} />&nbsp; &nbsp; </div>&nbsp; );}我还会有 CSS 样式来切换占位符和图像的display属性。.App {&nbsp; --image-height: 150px;&nbsp; --image-width: var(--image-height);}.imgWrapper {&nbsp; margin-bottom: 10px;}.img {&nbsp; height: var(--image-height);&nbsp; width: var(--image-width);}.imgLoader {&nbsp; height: 150px;&nbsp; width: 150px;&nbsp; background-color: red;}/* container is loading, hide the img */.imgWrapper--isLoading .img {&nbsp; display: none;}/* container not loading, display img */.imgWrapper:not(.imgWrapper--isLoading) .img {&nbsp; display: block;}/* container not loading, hide placeholder */.imgWrapper:not(.imgWrapper--isLoading) .imgLoader {&nbsp; display: none;}现在我的父组件将执行对所有图像 url 的请求。它也有自己的isLoading状态,当设置时true会显示自己的占位符。当图像 url 的请求得到解决时,我将映射到每个 url 以呈现我的Image组件。export default function App() {&nbsp; const [imageUrls, setImageUrls] = useState([]);&nbsp; const [isLoading, setIsLoading] = useState(true);&nbsp; useEffect(() => {&nbsp; &nbsp; fetchImages().then((response) => {&nbsp; &nbsp; &nbsp; setImageUrls(response);&nbsp; &nbsp; &nbsp; setIsLoading((prev) => !prev);&nbsp; &nbsp; });&nbsp; }, []);&nbsp; const images = imageUrls.map((url, index) => <Image key={index} src={url} />);&nbsp; return <div className="App">{isLoading ? "Please wait..." : images}</div>;}

慕码人2483693

有用于此的库,但如果您想推出自己的库,则可以使用IntersectionObserver,如下所示:const { useState, useRef, useEffect } = React;const LazyImage = (imageProps) => {&nbsp; const [shouldLoad, setShouldLoad] = useState(false);&nbsp; const placeholderRef = useRef(null);&nbsp; useEffect(() => {&nbsp; &nbsp; if (!shouldLoad && placeholderRef.current) {&nbsp; &nbsp; &nbsp; const observer = new IntersectionObserver(([{ intersectionRatio }]) => {&nbsp; &nbsp; &nbsp; &nbsp; if (intersectionRatio > 0) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; setShouldLoad(true);&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; });&nbsp; &nbsp; &nbsp; observer.observe(placeholderRef.current);&nbsp; &nbsp; &nbsp; return () => observer.disconnect();&nbsp; &nbsp; }&nbsp; }, [shouldLoad, placeholderRef]);&nbsp; return (shouldLoad&nbsp;&nbsp; &nbsp; ? <img {...imageProps}/>&nbsp;&nbsp; &nbsp; : <div className="img-placeholder" ref={placeholderRef}/>&nbsp; );};ReactDOM.render(&nbsp; <div className="scroll-list">&nbsp; &nbsp; <LazyImage src='https://i.insider.com/536a52d9ecad042e1fb1a778?width=1100&format=jpeg&auto=webp'/>&nbsp; &nbsp; <LazyImage src='https://www.denofgeek.com/wp-content/uploads/2019/12/power-rangers-beast-morphers-season-2-scaled.jpg?fit=2560%2C1440'/>&nbsp; &nbsp; <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'/>&nbsp; &nbsp; <LazyImage src='https://m.media-amazon.com/images/M/MV5BNTFiODY1NDItODc1Zi00MjE2LTk0MzQtNjExY2I1NTU3MzdiXkEyXkFqcGdeQXVyNzU1NzE3NTg@._V1_CR0,45,480,270_AL_UX477_CR0,0,477,268_AL_.jpg'/>&nbsp; </div>,&nbsp; document.getElementById('app'));.scroll-list > * {&nbsp; margin-top: 400px;}.img-placeholder {&nbsp; content: 'Placeholder!';&nbsp; width: 400px;&nbsp; height: 300px;&nbsp; border: 1px solid black;&nbsp; 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>此代码让它们在屏幕上显示占位符后立即加载,但如果您想要更大的检测余量,则可以调整 的rootMargin选项,IntersectionObserver以便它在仍然略微离开屏幕的情况下开始加载。

呼如林

将响应数据映射到“isLoading”布尔值数组,并更新回调以获取索引并更新特定的“isLoading”布尔值。function Sample() {&nbsp; const [items, setItems] = useState([]);&nbsp; const [imgLoading, setImgLoading] = useState([]);&nbsp; useEffect(() => {&nbsp; &nbsp; axios.get(url).then((response) => {&nbsp; &nbsp; &nbsp; const { data } = response;&nbsp; &nbsp; &nbsp; setItems(data);&nbsp; &nbsp; &nbsp; setImgLoading(data.map(() => true));&nbsp; &nbsp; });&nbsp; }, []);&nbsp; return items.map((item, index) => (&nbsp; &nbsp; <img&nbsp; &nbsp; &nbsp; src={item.imageUrl}&nbsp; &nbsp; &nbsp; onLoad={() =>&nbsp; &nbsp; &nbsp; &nbsp; setImgLoading((loading) =>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; loading.map((el, i) => (i === index ? false : el))&nbsp; &nbsp; &nbsp; &nbsp; )&nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; />&nbsp; ));}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

JavaScript