[React] 코드 분할 (React.lazy , Suspense)

young·2022년 7월 28일
0

7/21~8/18 Section 4 TIL

목록 보기
6/22

코드 분할 (Code Spliting)

앱이 커지면 번들도 커진다.

모던 웹 이전의 자바스크립트 코드는 최소한의 수준으로 작성되었다.

모던 웹으로 발전하면서 점점 DOM을 다루는 정도가 정교해지며 자바스크립트 코드 자체가 방대해지고 무거워졌다.

자바스크립트 엔진이 해석해야 하는 자바스크립트 코드 양이 많아져서
번들링 했을 때 특정 지점에서 코드를 해석하고 실행하는 정도가 느려지게 되었다.

코드 분할은 런타임에서 여러 번들을 동적으로 만들고 불러오는 것으로, Webpack, Rollup과 같은 번들러가 지원하는 기능이다.

"코드 분할은 여러분의 앱을 “지연 로딩” 하게 도와주고 앱 사용자에게 획기적인 성능 향상을 하게 합니다. 앱의 코드 양을 줄이지 않고도 사용자가 필요하지 않은 코드를 불러오지 않게 하며 앱의 초기화 로딩에 필요한 비용을 줄여줍니다."

import()

번들링되는 파일에는 서드파티 라이브러리도 포함된다.
서드파티 라이브러리는 사용자에게 다양한 메소드를 제공하기 때문에 코드의 양이 많고 번들링 시 많은 공간을 차지한다.

따라서 import문으로 라이브러리를 불러올 시 전체를 불러오지 않고,
필요한 메소드를 각각 불러와서 사용하는 것이 훨씬 좋다.

dynamic import

코드 파일의 최상위에서 import문으로 라이브러리 및 파일을 불러오는 것을 static import(정적 불러오기)라고 한다.

static import는 문서 최상위에 작성해야 하고, 블록문 안에 작성할 수 없다.

번들링시 코드 구조를 분석해 모듈을 한 데 모으고 사용하지 않는 모듈은 제거하는 등의 작업을 하는데, 코드 구조가 간단하고 고정이 되어 있을 때에만 작업이 가능하기 때문이다.

그러나 이제는 구문 분석 및 컴파일해야 하는 스크립트의 양을 최소화시키기 위해 dynamic import(동적 불러오기) 구문을 지원한다.

//Before
import OtherComponent from './OtherComponent';

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

React.lazy() & Suspense

React는 SPA이므로 한 번에 사용하지 않는 컴포넌트까지 불러오는 단점이 있으나,
React.lazy()를 통해 컴포넌트를 동적으로 import할 수 있기 때문에 초기 렌더링 지연 시간을 어느정도 줄일 수 있게 된다.
(e.g. 사용자가 Form을 제출하지 않으면 import하지 않고, 제출하면 Form 컴포넌트를 dynamic import한다.)

  • React.lazy()는 dynamic import를 호출하는 함수를 인자로 가진다.

  • React.lazy는 현재 default exports만 지원한다.

  • lazy 컴포넌트는 React.Suspense 컴포넌트 하위에서 렌더링 해야 한다.

import React, { Suspense } from 'react';

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

function MyComponent() {
  return (
    <div>
      <Suspense fallback={<div>Loading...</div>}>
        <section>
          <OtherComponent />
          <AnotherComponent />
        </section>
      </Suspense>
    </div>
  );
}
  • Suspense 컴포넌트는 lazy 컴포넌트가 로드 되길 기다리는 동안 예비 컨텐츠(fallback)를 보여줄 수 있도록 한다.

  • 하위 요소로 여러 개의 lazy 컴포넌트를 가질 수 있다.

Error boundaries

네트워크 장애와 같은 다른 모듈을 로드에 실패할 경우 발생하는 에러를 처리하는 컴포넌트는 lazy 컴포넌트를 감싼 Suspense 컴포넌트 상위에 위치시킨다.

import React, { Suspense } from 'react';
import MyErrorBoundary from './MyErrorBoundary';

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

const MyComponent = () => (
  <div>
    <MyErrorBoundary>
      <Suspense fallback={<div>Loading...</div>}>
        <section>
          <OtherComponent />
          <AnotherComponent />
        </section>
      </Suspense>
    </MyErrorBoundary>
  </div>
);

라우트 기반 코드 분할

import React, { Suspense, lazy } from 'react';
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';

const Home = lazy(() => import('./routes/Home'));
const About = lazy(() => import('./routes/About'));

const App = () => (
  <Router>
    <Suspense fallback={<div>Loading...</div>}>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/about" element={<About />} />
      </Routes>
    </Suspense>
  </Router>
);

중간에 코드 분할을 하는 것은 까다롭기 때문에 웹 페이지를 불러오고 진입하는 단계에서 코드 분할을 설정하는 것이 좋다.
하지만 페이지를 이동할 때마다 로딩 화면이 보여진다는 것을 고려해야 한다.


https://ko.reactjs.org/docs/code-splitting.html#code-splitting
https://create-react-app.dev/docs/code-splitting/
https://webpack.js.org/guides/code-splitting/

profile
즐겁게 공부하고 꾸준히 기록하는 나의 프론트엔드 공부일지

0개의 댓글