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 원인

  1. 사이즈가 정해져 있지 않은 이미지
  2. 사이즈가 정해져 있지 않은 광고
  3. 동적으로 삽입된 컨텐츠
  4. web font(FOIT, FOUT)

문제점

  1. 화면 상 위치를 다시 계산해야해 성능에 영향을 줌
  2. 사용성에 영향을 줌

해결

이미지 렌더링 사이즈가 화면 크기에 따라 동적으로 변하기 때문에 계산된 비율을 기반으로 사이즈를 지정해준다.

  • 변경 전
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를 사용해서 구현해보자.

간단하게 구현 가능한 장점이 있음.

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 숫자값을 주어 미리 로딩할 수도 있다.