109 리액트 - 이미지 레이지로드
source: categories/study/vue-experiance/vue-experiance_9-99_10.md
109 리액트 - 이미지 레이지로드
상황
- 이미지 로드되는 시점이 서로 다 달라서 처음 로드된 화면이 엉성하게 보이는 이슈
- 빠르게 로드된 이미지는 애니메이션 시작점부터 제대로 보여서 자연스러우나 애니메이션이 실행되고나서 진행된 도중에 로드된 이미지는 부자연스럽게 보임
- 또한 이미지 로드되는 시점이 서로 달라 처음 로딩시 영역이 뚝뚝 끊겨서 늘어나는 것처럼 보이는 현상도 발생
해결방법
- 아래 oxMain 클래스를 가진 요소에 opacity: 0 속성을 주었습니다.
lazy-load
를 적용해야하는img
태그에lazy-load
클래스명과lazy-src
속성을 적용했습니다.- 그리고
Promise
객체의allSettled
라는 static 메소드를 활용하여 lazy-load 클래스를 가지고있는 img 태그들의 이미지 로드가 완전히 끝나는 시점을 인식하도록 했습니다. - 이미지 로드가 완전히 끝나면
oxMain
요소에is_loaded
클래스를 추가하여opacity: 1
속성을 주었습니다.
Promise.allSettled 메소드와 Promise.all 메소드의 차이점
Promise.allSettled
메소드는 순회 가능한 객체를 통해 나열된 Promise 각각이 resolve를 하던 reject를하던 상관없이 각 Promise의 결과를 배열 형태로 반환합니다.Promise.all
메소드는 순회 가능한 객체를 통해 나열된 Promise들 중에서 어느것 하나라도 reject하는 경우 이를 사용해 자기 자신도 reject합니다.
이러한 차이 때문에 요즘은 Promise.all
보단 Promise.allSettled
메소드를 많이 사용한다고합니다.
import React, {useEffect, useRef} from 'react'
import './MainPage.css'
import imgTitle from '../../resources/picture/oxQuizTitle3.png';
import imgH1 from '../../resources/picture/h1_fix.png';
import imgH2 from '../../resources/picture/h2_fix.png';
import btnStart from '../../resources/picture/btnStart3.png';
import imgCloudMain from '../../resources/picture/cloudMain.png'
import imgHill from '../../resources/picture/hill3.png'
import {Link} from 'react-router-dom';
import lottie from 'lottie-web';
function MainPage() {
const container1 = useRef(null)
const container2 = useRef(null)
const container3 = useRef(null)
const imgLoad = () => {
const imgArr = Array.prototype.slice.call(document.querySelectorAll('.lazy-load'));
Promise.allSettled(imgArr.map((item, index) => {
return new Promise(resolve => {
item.addEventListener('load', () => {
resolve();
})
item.src = item.getAttribute('lazy-src');
})
}))
.then(_ => {
document.querySelector('.oxMain').classList.add('is_loaded');
})
.catch(err => console.log(err));
}
useEffect(() => {
lottie.loadAnimation({
container: container1.current,
renderer: 'svg',
loop: true,
autoplay: true,
animationData: require('../../resources/svg/lottie_gift.json'),
})
lottie.loadAnimation({
container: container2.current,
renderer: 'svg',
loop: true,
autoplay: true,
animationData: require('../../resources/svg/lottie_play1.json'),
})
lottie.loadAnimation({
container: container3.current,
renderer: 'svg',
loop: true,
autoplay: true,
animationData: require('../../resources/svg/lottie_play2.json'),
})
imgLoad();
}, [])
return (
<div className="oxMain">
<div className="LottieGift" ref={container1}/>
<div className="wrapImgTitle">
<img lazy-src={imgTitle} className="lazy-load imgTitle" alt=""/>
</div>
<div className="wrapImgH1">
<img lazy-src={imgH1} className="lazy-load imgH1" alt=""/>
</div>
<div className="wrapImgH2">
<img lazy-src={imgH2} className="lazy-load imgH2" alt=""/>
</div>
<div className="wrapButton">
<Link to="/quiz">
<img lazy-src={btnStart} className="lazy-load btnStart" alt=""/>
</Link>
</div>
<div className="wrapOtherImgs">
<img lazy-src={imgCloudMain} className="lazy-load imgCloudMain" alt=""/>
<img lazy-src={imgHill} className="lazy-load imgHill" alt=""/>
</div>
<div className="LottiePlay1" ref={container2}/>
<div className="LottiePlay2" ref={container3}/>
</div>
)
}
export default MainPage