code splitting을 위해 router 구조 변경하기
...
const BlogLayout = lazy(() => import("./pages/blogs/BlogLayout"));
const BlogOwnerPostList = lazy(() => import("./pages/blogs/BlogOwnerPostList"));
const BlogOwnerIntroduction = lazy(() => import("./pages/blogs/BlogOwnerIntroduction"));
export default function App() {
return (
<Routes>
<Route path="/" element={<RootLayout />}>
<Route index element={<Home />} />
...
<Route
path="blogs/:username"
element={
<Suspense fallback={<LazyPageLoadingMessage />}>
<BlogLayout />
</Suspense>
}
>
<Route index element={<BlogOwnerPostList />} />
<Route
path="introduction"
element={<BlogOwnerIntroduction />}
/>
</Route>
...
</Route>
<Route path="*" element={<NotFound />} />
</Routes>
);
}
-
react router의 nested routes를 사용 중이다.
-
"blogs/:username"
의(BlogLayout 컴포넌트) child route로index
와(BlogOwnerPostList 컴포넌트)"introduction"
을(BlogOwnerIntroduction 컴포넌트) 두었다. -
Route-based code splitting
을 위해 lazy 함수를 호출해 BlogLayout, BlogOwnerPostList, BlogOwnerIntroduction을lazy-loaded React component
로 만들었다. 따라서 이 컴포넌트들이 필요할 때, 컴포넌트 코드를 클라이언트로 가져온다. -
유저가
blogs/test-user
에 있다가 처음으로blogs/test-user/introduction
으로 이동하면 BlogOwnerIntroduction 컴포넌트 코드가 없기 때문에 BlogLayout을 감싸는 Suspense에 정해준 fallback이 rendering 된다.- BlogOwnerIntroduction과 가장 가까운 Suspense는 BlogLayout을 감싸는 Suspense이다.
- BlogOwnerIntroduction 코드를 가져오는 동안, BlogLayout 위치에 fallback이 나타나서 사용자 경험상 좋지 않다.
- 이를 해결하기 위해 child route의 컴포넌트인 BlogOwnerPostList, BlogOwnerIntroduction를 감싸는 Suspense를 별도로 둘 수 있다.
- child route의 컴포넌트 각각을 Suspense로 감싸는 것도 해결방안이 될 수 있지만, 사용자가 이미
blogs/*
위치에 있다면, blogs 하위에 있는 모든 컴포넌트를 한 번에 가져오는 것이 더 좋을 것 같다. - 이를 위해서 router의 구조를 살짝 변경해주어야 한다.
react router 문서에서 단일 route 이외에, route의 묶음도 lazy loading 하는 방법을 소개하고 있다.
-
blogs 관련 route들을 별도의
Routes
컴포넌트로 묶는다. 즉, blogs 관련 route를 분리한다.export default function Blogs() { return ( <Routes> <Route path="/" element={<BlogLayout />}> <Route index element={<BlogOwnerPostList />} /> <Route path="introduction" element={<BlogOwnerIntroduction />} /> </Route> <Route path="*" element={<NotFound />} /> </Routes> ); }
-
전체적인 라우팅을 하는 App 컴포넌트에서
lazy-loaded React component
로 선언된Blogs
컴포넌트를blogs/:username/*
와 연결하면 된다.blogs/:username
이 아니라 꼭blogs/:username/*
에 연결해야 한다.blogs/:username
에 연결하면 제대로 라우팅 되지 않는다.일반 컴포넌트
를(예를 들면,Home
컴포넌트) 라우트로 등록하는 것과Routes
를(Blogs
컴포넌트) 라우트로 등록하는 것의 차이점이다.... const Blogs = lazy(() => import("./pages/blogs/Blogs")); export default function App() { return ( <Routes> <Route path="/" element={<RootLayout />}> <Route index element={<Home />} /> ... <Route path="blogs/:username/*" element={ <Suspense fallback={<LazyPageLoadingMessage />}> <Blogs /> </Suspense> } /> ... </Route> <Route path="*" element={<NotFound />} /> </Routes> ); }
-
유저가
/blogs/test-user
를 처음 방문하는 순간 blogs 관련 컴포넌트 코드를 모두 가져온다.- 따라서 이후에
/blogs/test-user/introduction
에 처음 방문해도 loading indicator가 표시되지 않는다. 이미 관련 컴포넌트의 코드가 클라이언트에 있기 때문이다.
- 따라서 이후에
-
App 컴포넌트가 깔끔해졌다.
- blogs 관련 라우팅을 Blogs 컴포넌트가 처리하기 때문이다.