[React 스터디] 3 : 코드 분할
번들링
대부분 React 앱들은 Webpack, Rollup 또는 Browserify 같은 툴을 사용하여 여러 파일을 하나로 병합한 “번들된” 파일을 웹 페이지에 포함하여 한 번에 전체 앱을 로드할 수 있습니다.
번들이 거대해지는 것을 방지하기 위한 좋은 해결방법은 번들을 “나누는” 것입니다.
앱에 코드 분할을 도입하는 가장 좋은 방법은 동적 import() 문법을 사용하는 방법입니다.
before
1
2
3
4
5
6
7
8
9
// app.js
import { add } from "./math";
console.log(add(16, 26));
// math.js
export function add(a, b) {
return a + b;
}
after
1
2
3
import("./math").then((math) => {
console.log(math.add(16, 26));
});
Suspense
Suspense를 사용하면 컴포넌트가 렌더링되기 전까지 기다릴 수 있습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// 이것은 프라미스가 아닙니다. Suspense 통합에서 만들어낸 특별한 객체입니다.
const resource = fetchProfileData();
function ProfilePage() {
return (
<Suspense fallback={<h1>Loading profile...</h1>}>
<ProfileDetails />
<Suspense fallback={<h1>Loading posts...</h1>}>
<ProfileTimeline />
</Suspense>
</Suspense>
);
}
function ProfileDetails() {
// 아직 로딩이 완료되지 않았더라도, 사용자 정보 읽기를 시도합니다
const user = resource.user.read();
return <h1>{user.name}</h1>;
}
function ProfileTimeline() {
// 아직 로딩이 완료되지 않았더라도, 게시글 읽기를 시도합니다
const posts = resource.posts.read();
return (
<ul>
{posts.map((post) => (
<li key={post.id}>{post.text}</li>
))}
</ul>
);
}
화면 상에 <ProfilePage>
를 렌더링할 때에 아래와 같은 일들이 벌어집니다.
- fetchProfileData() 요청을 발동시킵니다.
<ProfilePage>
의 렌더링을 시도합니다.<ProfileDetails>
의 렌더링을 시도합니다. resource.user.read()를 호출합니다. 아직 불러온 데이터가 아무 것도 없으므로 다른 컴포넌트의 렌더링을 시도합니다.<ProfileTimeline>
의 렌더링을 시도합니다. resource.posts.read()를 호출합니다. 또 한번, 아직 데이터가 없으므로 다른 컴포넌트의 렌더링을 시도합니다.- 렌더링을 시도할 컴포넌트가 남아있지 않습니다.
<ProfileDetails>
가 정지된 상태이므로, React는 트리 상에서<ProfielDetails>
위에 존재하는 것 중 가장 가까운<Suspense>
Fallback을 찾습니다. 그것은<h1>
Loading profile…</h1>
입니다. 일단, 지금으로서는 할 일이 다 끝났습니다.
React.lazy
React.lazy 함수를 사용하면 동적 import를 사용해서 컴포넌트를 렌더링 할 수 있습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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>
);
}
lazy 컴포넌트는 Suspense 컴포넌트 하위에서 렌더링되어야 하며, 하나의 Suspense 컴포넌트로 여러 lazy 컴포넌트를 감쌀 수도 있습니다.
비동기식 반응 라우터
특정 Route에 있을 때만 컴포넌트를 로드할 수 있습니다.
다른 컴포넌트와 함께 사용할 때 특정 Route에 있을 때만 로드되도록 컴포넌트를 포장할 수 있습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import React, { Suspense, lazy } from "react";
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
const FunComponent = lazy(() => import("./FunComponent"));
const TerribleComponent = lazy(() => import("./TerribleComponent"));
const TestComponent = lazy(() => import("./TestComponent"));
const LoadingMessage = () => "I'm loading...";
const App = () => (
<Suspense fallback={<LoadingMessage />}>
<Switch>
<Route path="/fun">
<FunComponent />
</Route>
<Route path="/terrible">
<TerribleComponent />
</Route>
<Route>
<TestComponent />
</Route>
</Switch>
</Suspense>
);
Webpack - 모듈시스템과 번들링의 이해
React 공식 문서 - 코드 분할
React 공식 문서 - 데이터를 가져오기 위한 Suspense (실험 단계)
Async React using React Router & Suspense
This post is licensed under CC BY 4.0 by the author.