이미지 하나면 html에 다운 속도는 문제가 없는데 만약 이미지가 여러개면 유저가 페이지를 들어갈 때 바로 안보이고 다운로드가 완료된 이미지 먼저 보여준다.
하지만 이거는 사용자 경험에 안좋은 것이 되서 lazy loading을 시키면된다.
만약 백엔드에서 이미지를 받아올 때 img url을 img태그에 넣을 때
{
imgItem ? <img src={imgItem}/> : <div>로딩중..</div>
}
이런식으로 만들었는데 이런건 이미지를 위한 lazy loading이 아니다. 그래서 검색을 하였는데
stackover flow에서 Promise.all() 이거를 이용하여 이미지를 캡쳐한다고 한다.
물론 js를 사용했을 때 이걸로 개발을 했었는데 js에서는 Promise all 을 사용하여 모두 다 true가 되었을 때 다운로드 된 걸 div children에 직접 img 태그를 동적으로 추가했는데
이 부분은 react에 가상 dom을 이용했을때 상당히 않 좋기 때문에 다른 방식을 찾아 봤다.
const [imgsLoaded, setImgsLoaded] = useState(false);
useState를 하나 만든 후
useEffect(() => {
const loadImage = image => {
return new Promise((resolve, reject) => {
const loadImg = new Image()
loadImg.src = image.url
// wait 2 seconds to simulate loading time
loadImg.onload = () =>
setTimeout(() => {
resolve(image.url)
}, 2000)
loadImg.onerror = err => reject(err)
})
}
Promise.all(IMAGES.map(image => loadImage(image)))
.then(() => setImgsLoaded(true))
.catch(err => console.log("Failed to load images", err))
}, [])
첫 페이지로 들어올때 IMAGES에 이미지를 loadImage에 넣어서 만약 load가 성공했을때 true 실패했을 때는 실패로그를 내보내서
<>
<main className="images">
{imgsLoaded ? (
IMAGES.map(image => (
<img key={image.id} src={image.url} alt="Human" />
))
) : (
<h1>Loading images...</h1>
)}
</main>
</>
이렇게 넣어준다.
그래도 이미지 양이 몇 백개면 시간이 좀 걸릴 수 있지만 다 다운로드가 되었다면 한번에 다 보이기 때문에 사용자 경험쪽에선 보기에는 좋을 것이다.
참고 https://stackoverflow.com/questions/60847095/how-to-load-all-images-before-showing-the-page-in-react