Angular에서 컴포넌트를 동적으로 렌더링할까? 라우트로 분리할까?
앵귤러로 SPA(Single Page Application)를 개발하다 보면, 화면 전환을 어떻게 구성할지에 대한 고민이 꼭 생깁니다
"<app-example> 컴포넌트로 렌더할까? 아니면 route를 따로 만들어서 이동시키는 게 좋을까?"
결론부터 말하자면 "경우에 따라 다르다" 입니다.
두 방식 모두 장단점이 분명하며, 상황에 따라 선택이 달라져야 합니다.
1. 컴포넌트 인클루전 방식
<!-- main.component.html -->
<app-tab-one *ngIf="selectedTab === 'one'"></app-tab-one>
<app-tab-two *ngIf="selectedTab === 'two'"></app-tab-two>
// main.component.ts
ngOnInit() {
this.activatedRoute.queryParams.subscribe(params => {
this.selectedTab = params['tab'] ?? 'one';
});
}
장점
- 하나의 라우트에서 UI를 동적으로 전환할 수 있어 UX가 빠르고 부드럽다.
- DOM이 유지된 상태에서 상태를 전환하므로 리렌더링 비용이 적고, 복잡한 상태 전달도 용이.
- 내부 탭이나 모달처럼 URL 구조가 중요하지 않은 경우 빠른 개발이 가능.
단점
- URL만 봐서는 어떤 화면인지 알기 어렵다. (/main?tab=one → 의미 불분명)
- 브라우저 히스토리, 앞으로/뒤로 가기 동작이 어색할 수 있음.
- Lazy loading 불가능. 모든 컴포넌트가 초기 번들에 포함됨 → 성능 저하 우려.
사용 시기
- 탭 전환, 다중 동시 뷰 렌더링.
- SEO와 무관한 admin 페이지나 앱 내부 UI.
2. 라우트 분리 방식
// app-routing.module.ts
const routes: Routes = [
{ path: 'main/tab-one', component: TabOneComponent },
{ path: 'main/tab-two', component: TabTwoComponent },
];
<!-- main.component.html -->
<router-outlet></router-outlet>
장점
- URL 구조가 명확하다. (/main/tab-one → 명시적 경로)
- 브라우저 히스토리 지원, 북마크, 공유 등에서 유저 경험이 뛰어남.
- Lazy loading, preloading 전략 사용 가능 → 성능 최적화에 유리.
- SSR(서버 사이드 렌더링)과 SEO에 유리함.
단점
- 컴포넌트가 완전히 갈아끼워지기 때문에 상태 유지가 어렵다.
- UI 전환 속도가 느려질 수 있으며, 로딩 처리도 신경 써야 함.
- 복잡한 탭 UI에서 URL 관리가 오히려 개발 비용을 증가시킬 수 있음.
사용 시기
- 독립적인 페이지 역할을 하는 경우.
- SEO, 접근성, 공유 등 URL 의미가 중요한 화면.
- Lazy loading을 통한 성능 개선이 필요한 대규모 앱.
선택 기준 정리
| 상황 | 추천 방식 | 이유 |
| 탭 UI, 내부 상태 전환 | 컴포넌트 인클루전 | 빠른 전환과 상태 공유에 유리하며 라우트가 필요 없음 |
| 명확한 URL 필요 | 라우트 분리 | URL만으로 어떤 화면인지 식별 가능함 |
| 공유 가능한 화면 | 라우트 분리 | URL 복사/북마크/뒤로가기 등 지원이 자연스러움 |
| Lazy loading 필요 | 라우트 분리 | 페이지 단위 로딩으로 성능 최적화 가능 |
| 빠른 전환, 작은 범위 UI | 컴포넌트 인클루전 | 라우트 변경 없는 즉각적인 UI 렌더링이 가능함 |
| SSR, SEO 고려 | 라우트 분리 | 각 화면이 독립된 경로를 가지기 때문에 크롤러 최적화에 유리 |
'개발 공부 > Angular' 카테고리의 다른 글
| 앵귤러 동적 라우팅(Dynamic Routing) (0) | 2025.05.31 |
|---|---|
| RxJS 연산자 debounceTime, switchMap, mergeMap (1) | 2025.05.29 |
| Angular computed() (0) | 2025.05.26 |
| @HostListener (0) | 2025.05.19 |
| Angular Directive (0) | 2025.05.17 |