React 코드분할

박세영·2022년 7월 8일
0

이 글은 React v18.0.0 공식페이지에 있는 코드 분할 문서를 정리한 것입니다.
코드 분할

코드 분할

번들링

대부분 React 앱들은 Webpack, Rollup, Browserify 같은 툴을 통해 여러 파일을 하나의 파일로 번들링 한 다음 한 번에 전체 앱을 로드한다.

CRA, Next.js, Gatsby 와 같은 도구를 사용한다면 앱에서 Webpack이 같이 설정되어 있을 것이다. 그렇지 않다면 번들러를 통해 직접 설정을 해주어야 한다.

코드 분할

번들링은 훌륭한 도구이지만 앱이 커지면 번들의 사이즈 역시 커진다. 특히 큰 규모의 외부 라이브러리를 의존할 때 앱이 커져 로딩 시간이 길어지는 문제가 흔히 발생한다.

번들이 지나치게 거대해지는 것을 방지하기 위한 가장 좋은 해결방법은 번들을 분할하는 것이다. 코드 분할은 런타임에 여러 번들을 동적으로 만들고 불러오는 것으로 Webpack과 같은 번들러가 이런 기능을 지원한다.

코드 분할은 앱을 'lazy'하게 로딩하도록 도와주고 이를 통해 사용자 경험을 향상시킨다. 앱의 필요없는 부분을 로딩하지 않아 첫 로딩에 필요한 비용을 줄여준다.

import()

앱에 코드 분할을 도입하는 방법 중 가장 간단한 형태는 동적 import() 구문을 사용하는 것이다.

Before

import { add } from './math';

console.log(add(2, 4));

After

import('./math').then(math => {
	console.log(add(2, 4));
});

React.lazy

React.lazy 함수를 사용하면 동적 import를 사용해서 컴포넌트를 렌더링 할 수 있다.

Before

import otherComponent from './otherComponent';

After

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

MyComponent가 처음 렌더링 될 때 OtherComponent를 포함한 번들을 자동으로 불러온다.

React.lazy()는 동적 import()를 호출하는 함수를 인자로 가진다. 이 함수는 React 컴포넌트를 default export로 가진 모듈 객체가 이행되는 Promise를 반환해야 한다.

lazy컴포넌트는 Suspense 컴포넌트 하위에서 렌더링되어야 하며, Suspense는 lazy 컴포넌트가 로드되길 기다리는 동안 로딩 화면과 같은 예비 컨텐츠를 보여줄 수 있게 해준다.

import React, { Suspense } from 'react';

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

function MyComponent() {
	return (
    	<div>
        	<Suspense fallback={<div>Loading...</div>}>
            	<OtherComponent />
            </Suspense>
        </div>
    )
}

fallback prop은 컴포넌트가 로드될 때까지 기다리는 동안 렌더링하려는 React 엘리먼트를 받아들인다. Suspense 컴포넌트는 lazy 컴포넌트를 감싼다. 하나의 Suspense 컴포넌트로 여러 lazy 컴포넌트를 감쌀 수도 있다.

Route-based code splitting

앱에 코드 분할을 어느 곳에 도입할지 결정하는 것은 까다롭다. 따라서 개발자는 사용자의 경험을 해치지 않으면서 번들을 효율적으로 나누기 위해 고민해야 한다.

이를 시작하기 좋은 장소는 라우트이다. 아래와 같이 라우트 별로 코드를 분할 할 수 있다.

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>
);

Named Exports

React.lazy는 현재 default exports만 지원한다. named exports를 사용하고자 한다면 default로 이름을 재정의한 중간 모듈을 활용하면 된다. 이렇게 하면 tree shaking이 계속 동작하고 사용하지 않는 컴포넌트는 가져오지 않는다.

// ManyComponents.js
export const MyComponent = /* ... */;
export const MyUnusedComponent = /* ... */;
// MyComponent.js
export { MyComponent as default } from "./ManyComponents.js";
// MyApp.js
import React, { lazy } from 'react';
const MyComponent = lazy(() => import("./MyComponent.js"));

0개의 댓글