리액트 최적화

서성원·2025년 1월 13일
0

리액트

목록 보기
23/26
post-thumbnail

리액트 리렌더링 방지

React.memo의 기본동작

React.memo는 props의 얕은 비교를 통해 자식 컴포넌트가 받을 props가 이전과 동일한 경우, 자식 컴포넌트의 리렌더링을 방지한다.

➡️ 자식 컴포넌트가 리렌더링 되지 않는 경우

  1. 부모가 렌더링되어도 자식에게 전달된 props가 참조적으로 동일할 때
  2. 자식 컴포넌트 내부의 상태나 context 값이 변경되지 않을 때

🤔 부모 렌더링 시 자식 리렌더링이 발생하는 경우

1. props로 전달된 값이 새로운 참조를 가질 때

  • 부모 컴포넌트가 렌더링될 때, 자식에게 전달된 props가 새로 생성되면 참조값이 변경되어 React.memo가 이전 값과 다르다고 판단한다.
const Parent = () => {
  const arr = [1, 2, 3]; // 매번 새로운 배열 생성
  return <Child data={arr} />;
};

const Child = React.memo(({ data }) => {
  console.log("Child re-rendered");
  return <div>{data.join(", ")}</div>;
});

🔨useMemo로 참조값 고정하기

const Parent = () => {
  const arr = useMemo(() => [1, 2, 3], []); // 동일 참조 유지
  return <Child data={arr} />;
};

2. props로 전달된 함수가 새로운 참조를 가진 경우

const Parent = () => {
  const handleClick = () => console.log("Clicked");
  return <Child onClick={handleClick} />;
};

const Child = React.memo(({ onClick }) => {
  console.log("Child re-rendered");
  return <button onClick={onClick}>Click me</button>;
});

🔨useCallback으로 참조값 고정하기

const Parent = () => {
  const handleClick = useCallback(() => console.log("Clicked"), []);
  return <Child onClick={handleClick} />;
};

3. Context 값을 사용하는 경우

  • 자식 컴포넌트가 Context 값을 직접 사용하는 경우, 부모 렌더링과 관계없이 Context 값이 변경되면 자식이 리렌더링된다. 이런 경우 불필요한 렌더링이 발생할 수 있다.
const MyContext = React.createContext();

const Parent = () => {
  const value = { name: "John" };
  return (
    <MyContext.Provider value={value}>
      <Child />
    </MyContext.Provider>
  );
};

const Child = React.memo(() => {
  const contextValue = useContext(MyContext);
  console.log("Child re-rendered");
  return <div>{contextValue.name}</div>;
});

최적화 방법은 Context 값을 최소한의 책임으로 나누거나, useMemo로 Context 값의 참조를 고정해야 한다.

이미지 최적화

이미지 크기나 용량, 지연 시간 등 프로젝트를 하면서 직접 적용했던 최적화 방법을 소개하고자 합니다.

WebP란

Google은 온라인 이미지의 크기를 줄이기 위해 WebP 파일 포맷을 개발했습니다. 사진과 그래픽의 크기를 줄여 웹사이트가 빨리 로드되도록 할 수 있는데요. JPEG를 대체하기 위해 제시되었습니다.

웹사이트의 트래픽 감소 및 로딩 시간 단축을 목적으로, 사진 이미지 압축 효과가 높은 것으로 알려져 있습니다.

WebP의 장점

  1. 효율적인 압축
  • JPEG보다 20% 이상 더 적은 용량으로 이미지를 압축합니다.
  • PNG보다 더 작은 용량으로 투명도를 지원합니다.
  1. 애니메이션 지원
  • GIF 대신 WebP로 파일 크기를 줄여 애니메이션을 사용할 수 있습니다.
  1. 브라우저 지원
  • 대부분의 브라우저는 WebP를 지원합니다. (Safari는 14버전 이상에서만 가능합니다.)
<img
  src="/pop_singer4.webp"
  loading="lazy"
  alt="Camila Cabello"
/>

여느 확장자와 같이 .webp로 이미지를 불러올 수 있습니다.

Lazy Loading

img태그의 loading="lazy" 속성은 이미지가 화면에 보이기 전까지 로딩되지 않도록 합니다. 사용자가 스크롤하여 이미지를 볼 위치에 도달하면, 그때 이미지를 로드하기 때문에 초기 페이지 로딩 속도를 개선할 수 있습니다.

저는 여러 이미지가 들어가는 페이지를 제작해야 했었고 아래의 방법으로 구현하였습니다.

import React from 'react';

const LazyImage = ({ src, alt, ...props }) => {
  return <img src={src} alt={alt} loading="lazy" {...props} />;
};

export default LazyImage;

img태그를 가져와 무조건 loading="lazy로 적용하는 컴포넌트를 만들었습니다.

<LazyImage
  src="/pop_singer4.webp"
  loading="lazy"
  alt="Camila Cabello"
/>

img태그 대신 LazyImage로 지연 로딩을 적용하였습니다. 지연 로딩뿐만 아니라 다른 속성들도 컴포넌트로 묶어 사용해봐도 좋을 것 같네요.

오디오 최적화

mp3 확장자

  • 손실 압축 알고리즘으로 파일 크기를 제공
  • 오디오 로딩 속도 향상
  • 사용자 데이터 사용량 절감

프로젝트에서 음악을 재생해야 할 때가 있었는데 제공받은 wav확장자를 가진 파일이 로컬에서는 지연없이 잘 재생되었다. 하지만 배포사이트에서 2~3초 지연되고 재생되는 문제가 생겼다. 확장자를 mp3로 바꾸니 1초 이내로 지연이 줄어듦은 확인할 수 있었다.

또한, 기존 용량은 5MB이었으나 확장자를 바꾸고 용량이 줄어듦을 확인할 수 있었다.

Image 1 Image 2

preload

audio태그에는 preload라는 속성이 존재한다. 해당 속성을 none로 설정한다면 사용자가 클릭할 시 음악 파일이 로드된다.

따로 속성을 설정해주지 않는다면 preload의 기본값이 auto가 된다. 이것은 컴포넌트 마운트 시 오디오를 미리 로드하게 되어, 당장 필요없는 음악 파일까지 모두 로드하게 된다.

적용한 코드

 <audio
   preload="none"
   ref={(el) => (audioRefs.current[item.audio] = el)}
/>

마치며

제대로 사용해보지 못한 useMemo나 useCallback을 새로 알 수 있게 되었습니다. 리액트 공식문서에도 다양한 사용법이 있어 제대로 공부해보려 합니다.

추가로 프로젝트를 하면서 적용했던 이미지, 오디오 최적화 방법을 정리해봤습니다. 최적화 전의 웹사이트 성능을 측정하지 않아 정확한 지표를 보여주지 못함에 아쉬움이 남네요. 기록의 필요성을 느꼈던 이번 포스트였습니다.

profile
FrontEnd Developer

0개의 댓글

관련 채용 정보