React 16.6 Suspense와 lazy 컴포넌트 도입기
문제 상황
사내 관리자 페이지의 초기 번들 사이즈가 1.2MB에 달했다. 사용자들이 접근하지 않는 페이지까지 모두 로드되고 있었고, 느린 네트워크 환경에서 초기 로딩 시간이 5초를 넘겼다.
React.lazy와 Suspense
React 16.6에서 공식 지원하기 시작한 코드 스플리팅 기능이다. 기존에 react-loadable 같은 서드파티 라이브러리를 사용했는데, 이제 공식 API로 제공된다.
import React, { Suspense, lazy } from 'react';
const AdminDashboard = lazy(() => import('./pages/AdminDashboard'));
const UserManagement = lazy(() => import('./pages/UserManagement'));
const Statistics = lazy(() => import('./pages/Statistics'));
function App() {
return (
<Router>
<Suspense fallback={<div>로딩 중...</div>}>
<Switch>
<Route path="/admin" component={AdminDashboard} />
<Route path="/users" component={UserManagement} />
<Route path="/stats" component={Statistics} />
</Switch>
</Suspense>
</Router>
);
}
적용 결과
- 초기 번들: 1.2MB → 850KB (29% 감소)
- 초기 로딩: 5.2초 → 3.1초
- Lighthouse 점수: 62 → 78
통계 페이지처럼 Chart.js 같은 무거운 라이브러리를 사용하는 곳에서 효과가 컸다. 해당 페이지 접근 시에만 차트 라이브러리가 로드되도록 분리했다.
주의사항
Suspense는 아직 SSR을 지원하지 않는다. Next.js 프로젝트에는 적용하지 못하고, CRA 기반 SPA에만 적용했다. fallback UI를 너무 단순하게 만들면 깜빡임이 심해 보이니, 최소한의 레이아웃 스켈레톤은 유지하는 게 좋았다.
다음 단계
Route 레벨뿐 아니라 Modal이나 Drawer 같은 조건부 렌더링 컴포넌트에도 적용해볼 계획이다. Webpack Bundle Analyzer로 chunk 분석을 더 세밀하게 해서 최적화 포인트를 찾아야겠다.