대규모 React 애플리케이션에서는 초기 로딩 속도가 사용자 경험을 크게 좌우합니다. 모든 컴포넌트를 한 번에 번들링하면 번들 크기가 커지고, 네트워크 전송 및 파싱에 오래 걸리게 됩니다. 이를 해결하기 위해 코드 분할(Code Splitting)과 지연 로딩(Lazy Loading)을 활용해 필요한 시점에만 코드를 로드하는 전략을 적용합니다.
1. 코드 분할이란?
코드 분할은 하나의 큰 번들을 여러 개의 작은 청크(chunk)로 나누는 작업입니다. Webpack, Vite 등 번들러가 이를 지원하며, React에서는 React.lazy와 Suspense를 사용해 손쉽게 구현할 수 있습니다.
2. 기본적인 구현 방법
import React, { Suspense, lazy } from 'react';
// 페이지별 컴포넌트를 lazy 로 로드
const Home = lazy(() => import('./pages/Home'));
const About = lazy(() => import('./pages/About'));
function App() {
return (
<Suspense fallback={<div>Loading…</div>}>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
</Routes>
</Suspense>
);
}
export default App;
위 예시처럼 라우트 레벨에서 컴포넌트를 분리하면, 사용자가 해당 경로에 접근할 때만 해당 청크를 다운로드합니다.
3. 라우트 기반 코드 분할 (React Router v6)
React Router v6에서는 lazy와 Outlet을 결합해 중첩 라우트까지 손쉽게 분할할 수 있습니다.
import { createBrowserRouter, RouterProvider } from 'react-router-dom';
import { Suspense, lazy } from 'react';
const Dashboard = lazy(() => import('./pages/Dashboard'));
const Settings = lazy(() => import('./pages/Settings'));
const router = createBrowserRouter([
{
path: '/',
element: <RootLayout />, // 공통 레이아웃
children: [
{ index: true, element: <Home /> },
{
path: 'dashboard',
element: (
<Suspense fallback={<div>Loading Dashboard…</div>}>
<Dashboard />
</Suspense>
),
children: [
{
path: 'settings',
element: (
<Suspense fallback={<div>Loading Settings…</div>}>
<Settings />
</Suspense>
),
},
],
},
],
},
]);
function App() {
return <RouterProvider router={router} />;
}
export default App;
4. 동적 import 로 컴포넌트 외부 라이브러리 지연 로딩
특정 UI 라이브러리나 차트 라이브러리는 무겁기 때문에, 사용자가 실제로 차트를 볼 때만 로드하도록 할 수 있습니다.
const Chart = lazy(() => import('react-apexcharts'));
function Stats() {
const [show, setShow] = React.useState(false);
return (
<div>
<button onClick={() => setShow(true)}>차트 보기</button>
{show && (
<Suspense fallback={<div>Loading chart…</div>}>
<Chart options={...} series={...} type="line" />
</Suspense>
)}
</div>
);
}
5. Webpack Chunk 이름 지정
디버깅과 네트워크 모니터링을 편리하게 하기 위해 청크 이름을 직접 지정할 수 있습니다.
const AdminPanel = lazy(() => import(/* webpackChunkName: "admin-panel" */ './pages/AdminPanel'));
Chrome DevTools > Network 탭에서 admin-panel.js 파일이 별도로 로드되는 것을 확인할 수 있습니다.
6. 성능 모니터링
코드 분할 적용 후 반드시 Lighthouse와 Web Vitals를 통해 다음 지표를 검증합니다.
- First Contentful Paint (FCP) 감소
- Largest Contentful Paint (LCP) 개선
- Total Blocking Time (TBT) 감소
또한 webpack-bundle-analyzer를 이용해 청크 크기를 시각화하고, 불필요하게 큰 청크가 없는지 점검합니다.
7. 실전 팁
- 페이지 진입 직전
preload혹은prefetch를 활용해 사용자가 곧 방문할 가능성이 높은 청크를 미리 받아두세요. - SSR(서버 사이드 렌더링)과 결합할 경우
loadable-components를 사용하면 서버와 클라이언트 모두에서 청크 매핑을 일관되게 처리할 수 있습니다. - React 18부터 도입된
Suspensefor data fetching 과 함께 사용하면 API 데이터 로드와 컴포넌트 로드를 동시에 최적화할 수 있습니다.
코드 분할과 지연 로딩을 적절히 적용하면 초기 번들 크기를 크게 줄이고, 사용자에게 빠른 인터랙티브 경험을 제공할 수 있습니다. 프로젝트에 맞는 청크 전략을 설계하고, 지속적인 성능 모니터링을 통해 최적화 상태를 유지하세요.
'React' 카테고리의 다른 글
| React 앱에서 이미지 압축과 최적화를 통한 성능 개선 (0) | 2026.08.31 |
|---|---|
| React에서 React.lazy와 Suspense를 사용한 컴포넌트 로딩 관리 (0) | 2026.08.31 |
| React에서 Playwright를 활용한 브라우저 자동화 테스팅 (0) | 2026.08.30 |
| React 앱에서 Cypress를 사용한 E2E 테스팅 구축하기 (0) | 2026.08.29 |
| React에서 Jest와 함께 유닛 테스팅 및 인테그레이션 테스팅 (0) | 2026.08.28 |