web
[React 최적화] 실습 4. 이미지 갤러리 페이지(1) - Layout Shift, react-lazyload
Jaaaay
2022. 8. 3. 15:43
실습내용
- 이미지 지연(lazy) 로딩
→ 로딩 성능 최적화
- Layout Shift 피하기
- useSelector 렌더링 문제 해결
- Redux Reselect를 통한 렌더링 최적화
- 병목 함수에 memoization 적용
- 병목 함수 로직 개선하기
→ 렌더링 성능 최적화
Layout Shift 피하기
화면 상의 이미지, 텍스트 등의 엘리먼트들이 위치, 크기 등에 변화가 일어나는 것
performance 탭과 Lighthouse에서도 Layout Shift가 일어난 것을 확인할 수 있다.
Layout Shift 원인
- 사이즈가 정해져 있지 않은 이미지
- 사이즈가 정해져 있지 않은 광고
- 동적으로 삽입된 컨텐츠
- web font(FOIT, FOUT)
문제점
- 화면 상 위치를 다시 계산해야해 성능에 영향을 줌
- 사용성에 영향을 줌
해결
이미지 렌더링 사이즈가 화면 크기에 따라 동적으로 변하기 때문에 계산된 비율을 기반으로 사이즈를 지정해준다.
- 변경 전
import React from 'react';
import styled from 'styled-components';
import { useDispatch } from 'react-redux';
import { showModal } from '../redux/imageModal';
function PhotoItem({ photo: { urls, alt } }) {
const dispatch = useDispatch();
const openModal = () => {
dispatch(showModal({ src: urls.full, alt }));
};
return (
<ImageWrap>
<Image src={urls.small} alt={alt} onClick={openModal} />
</ImageWrap>
);
}
const ImageWrap = styled.div``;
const Image = styled.img`
cursor: pointer;
width: 100%;
`;
export default PhotoItem;
- 변경 후
import React from 'react';
import styled from 'styled-components';
import { useDispatch } from 'react-redux';
import { showModal } from '../redux/imageModal';
function PhotoItem({ photo: { urls, alt } }) {
const dispatch = useDispatch();
const openModal = () => {
dispatch(showModal({ src: urls.full, alt }));
};
return (
<ImageWrap>
<Image src={urls.small} alt={alt} onClick={openModal} />
</ImageWrap>
);
}
const ImageWrap = styled.div`
width: 100%;
padding-bottom: 56.25%;
position: relative;
`;
const Image = styled.img`
cursor: pointer;
width: 100%;
position: absolute;
height: 100%;
top: 0;
left: 0;
`;
export default PhotoItem;
image에 wrapper를 활용하여 이미지 요소는 wrapper에 따라 정해지도록 한다.
이미지는 top, left에 0으로 지정하고, wrapper의 비율은 padding-bottom에 가로에 대한 세로 길이의 퍼센트 비율을 할당한다.
wrapper를 relative로, image를 absolute로 지정한다.
Layout Shift 값의 변화를 확인할 수 있다.
이미지 지연(lazy) 로딩(react-lazyload)
저번에는 intersection observer를 사용해서 레이지 로딩을 구현했는데, 이번에는 react-lazyload를 사용해서 구현해보자.
간단하게 구현 가능한 장점이 있음.
import React from 'react';
import styled from 'styled-components';
import LazyLoad from 'react-lazyload';
import { useDispatch } from 'react-redux';
import { showModal } from '../redux/imageModal';
function PhotoItem({ photo: { urls, alt } }) {
const dispatch = useDispatch();
const openModal = () => {
dispatch(showModal({ src: urls.full, alt }));
};
return (
<ImageWrap>
<LazyLoad>
<Image src={urls.small} alt={alt} onClick={openModal} />
</LazyLoad>
</ImageWrap>
);
}
LazyLoad 태그에 offset 속성에 px 숫자값을 주어 미리 로딩할 수도 있다.