Reputation: 1068
First of all I'm using ReactJS and I have the following simplified code snippet:
const Page = () => {
const [isLoading, setIsLoading] = useState(true);
return (
<Loading isLoading={isLoading} >
<img src='https://example.com/img1' alt='image' />
<img src='https://example.com/img2' alt='image' />
<img src='https://example.com/img3' alt='image' />
<img src='https://example.com/img4' alt='image' />
<img src='https://example.com/img5' alt='image' />
<img src='https://example.com/img6' alt='image' />
<img src='https://example.com/img7' alt='image' />
</Loading>
)
}
The problem:
The images are displayed progressively, and one after one, which doesn't look good, like the following example:
The solution that I'm searching for:
I wanna show the <Loading>
component by setting the variable isLoading
to true
after finishing the loading of the images.
So when the page is opened, first the user sees a loading page, then after loading all the images, the variable isLoading
is set to false, to hide the <Loading>
component.
Upvotes: 1
Views: 2017
Reputation: 4308
I was looking for the same solution, but I also wanted to be able to show a placeholder and something in case of an error.
In the end I settled for showing a placeholder image that would load almost instantly, and then replace it with the real deal once it is loaded:
import { useState } from 'react'
const LOADING_PREVIEW_IMAGE_PATH = '/pics/loading-preview-image.png'
const FAILED_LOAD_IMAGE_PATH = '/pics/failed-load-image.png'
function Image(realImageUrl) {
const [isPreviewImageLoadedState, setPreviewImageLoaded] =
useState({image: LOADING_PREVIEW_IMAGE_PATH, error: false})
return (
<img src={isPreviewImageLoadedState.image}
onLoad={() => {
// Need to check if there was an error, or it will enter a loop where
// the empty image will oscillates between being loaded and the error image
if (!isPreviewImageLoadedState.error) {
setPreviewImageLoaded({image: realImageUrl, error: false})
}
}}
onError={() => setPreviewImageLoaded({image: FAILED_LOAD_IMAGE_PATH, error: true})}
/>
)
}
You may have to tweak a thing or two if you want to replace the image with different one (like setting the key={}
to a Component up the chain). Just began learning ReactJS about 1 or 2 weeks ago, so take this suggestion with a pinch of salt.
Upvotes: 0
Reputation: 730
You can use onLoad
attribute for your purpose.
const Page = () => {
const [imageLoaded, setImageLoaded] = useState({});
const handleLoadImage = (image) => {
setImageLoaded(prev => {...prev, [image]: true});
}
const isLoading = useMemo(
() => !(imagedLoaded.img1 && imagedLoaded.img2 && imagedLoaded.img3 && imagedLoaded.img4 && imagedLoaded.img5 && imagedLoaded.img6 && imagedLoaded.img7)
, [imageLoaded]
)
return (
<Loading isLoading={isLoading} >
<img onLoad={() => handleLoadImage("img1")} src={imgURL1} alt='image' />
<img onLoad={() => handleLoadImage("img2")} src={imgURL2} alt='image' />
<img onLoad={() => handleLoadImage("img3")} src={imgURL3} alt='image' />
<img onLoad={() => handleLoadImage("img4")} src={imgURL4} alt='image' />
<img onLoad={() => handleLoadImage("img5")} src={imgURL5} alt='image' />
<img onLoad={() => handleLoadImage("img6")} src={imgURL6} alt='image' />
<img onLoad={() => handleLoadImage("img7")} src={imgURL7} alt='image' />
</Loading>
)
}
Upvotes: 1