[React] 코드 스플리팅(code spliting) - 성능 최적화

김건휘·2024년 10월 17일
0

React

목록 보기
9/19

이번시간에는 진행하고 있는 프로젝트에서 컴포넌트 코드 스플리팅(code spliting) 을 통해 로딩 속도 개선에 대한 이야기를 간단하게 나누어보고자 한다.

React에서의 코드 분할

React는 SPA(Single-Page-Application)인데, 사용하지 않는 모든 컴포넌트까지 한 번에 불러오기 때문에 첫 화면이 렌더링 될때까지의 시간이 오래걸린다. 그래서 사용하지 않는 컴포넌트는 필요한 시점에 로딩하는 방법을 통해서 초기 랜더링 지연시간을 개선할 수 있다.

React에서 코드 분할하는 방법은 dynamic import(동적 불러오기)를 사용하는 것이다. 그 전까지는 코드 파일의 가장 최상위에서 import 지시자를 사용해 사용하고자 하는 라이브러리 및 파일을 불러오는 방법을 사용했었습니다. 이를 static import(정적 불러오기)라고 한다.

React.lazy()

React.lazy 함수를 사용하면 dynamic import를 사용해 컴포넌트를 렌더링할 수 있다. React는 SPA(Single-Page-Application)이므로 한 번에 사용하지 않는 컴포넌트까지 불러오는 단점이 있다고 앞의 챕터에서 이야기했다. React는 React.lazy를 통해 컴포넌트를 동적으로 import를 할 수 있기 때문에 이를 사용하면 초기 렌더링 지연시간을 어느정도 줄일 수 있게 된다.

/* React.lazy로 dynamic import를 감싸준다. */
const Calendar = lazy(() => import('@/shared/components/Calendar'));

React.lazy로 감싼 컴포넌트는 단독으로 쓰일 수는 없고, React.suspense 컴포넌트의 하위에서 렌더링을 해야 한다.

Suspense

아래 코드처럼 lazy를 통해 import하면 해당 컴포넌트를 불러오는 시점에 로딩하는 시간이 생기게 된다. Suspense는 아직 렌더링이 준비되지 않은 컴포넌트가 있을 때 로딩 화면을 보여주고, 로딩이 완료되면 렌더링이 준비된 컴포넌트를 보여주는 기능입니다.

/* suspense 기능을 사용하기 위해서는 import 해와야 한다. */
import { Suspense } from 'react';

const OtherComponent = React.lazy(() => import('./OtherComponent'));
const AnotherComponent = React.lazy(() => import('./AnotherComponent'));

function MyComponent() {
  return (
    <div>
			{/* 이런 식으로 React.lazy로 감싼 컴포넌트를 Suspense 컴포넌트의 하위에 렌더링합니다. */}
      <Suspense fallback={<div>Loading...</div>}>
				{/* Suspense 컴포넌트 하위에 여러 개의 lazy 컴포넌트를 렌더링시킬 수 있습니다. */}
        <OtherComponent />
				<AnotherComponent />
      </Suspense>
    </div>
  );
}

Supense 컴포넌트의 fallback prop은 컴포넌트가 로드될 때까지 기다리는 동안 로딩 화면으로 보여줄 React 엘리먼트를 받아들인다. Suspense 컴포넌트 하나로 여러 개의 lazy 컴포넌트를 보여줄 수도 있다.



해당 사진은 제가 진행하고 있는 프로젝트에서 lazy를 적용하지 않았을 때의 Treemap과 성능 지표이다. 초기 HomePage를 로딩하는데 필요하지 않은 DatePicker(캘린더) 번들도 꽤나 많은 용량을 차지하고 있다.




해당 사진은 lazy를 적용한 후의 Treemap과 성능 지표이다. 초기 HomePage를 로딩에 DatePicker(캘린더) 번들을 불러오고 있지 않고, 성능이 개선된 것을 확인할 수 있다.

하지만 lazy로딩suspense로 동적으로 컴포넌트를 임포트를하게 되면 해당 컴포넌트를 사용하는 시점에 로딩이 발생할 수 있어서 오히려 성능을 저해하거나 사용자 경험을 저해하지 않을까?

정답은 그렇다이다.

Lazy Loading의 단점과 문제점

  • 사용자 인터랙션 시 지연 발생
    사용자가 특정 컴포넌트에 접근할 때마다 네트워크 요청이 발생하면 해당 컴포넌트가 렌더링되기 전에 지연이 발생한다.
  • 네트워크 지연 문제
    사용자가 네트워크 속도가 느린 환경에 있으면 lazy-loaded 컴포넌트가 로드되는 데 시간이 걸릴 수 있다.

해결 방안

Preloading을 활용하는 것이다. onMouseEnter와 같은 속성을 활용하여 lazy로딩이 적용된 컴포넌트가 사용되는 시점을 미리 예측하여 불러오는 것이다.


해당 영상을 확인해보면 날짜토글 버튼에 마우스가 올라가면 Calendar를 불러오고 있는 것을 네트워크탭에서 확인할 수 있다.

해당 프로젝트의 로직을 살펴보면 날짜 토글버튼을 클릭하면 Calendar을 불러와야한다. 그렇기 때문에 onMouseEnter속성을 활용하여 날짜 토글버튼에 마우스가 올라가면(사용자가 토글버튼을 클릭할 것을 예상) Calendar를 Preload(미리로드)하여 지연이 발생할 수 있는 문제를 해결할 수 있었다.

마무리

lazy loadingSuspense는 적절히 사용하면 성능 향상에 도움이 되지만, 무분별하게 사용하면 오히려 사용자 경험을 해칠 수 있다. 이를 해결하기 위해 preloading과 로딩 UI 제공, 코드 스플리팅 전략을 함께 활용하면 성능과 UX를 모두 개선할 수 있다.

상황에 따라 필요한 시점에 맞는 전략을 사용하는 것이 가장 핵심이다!!

profile
공유할 때 행복을 느끼는 프론트엔드 개발자

0개의 댓글