Angular는 Google이 개발하고 유지보수하는 TypeScript 기반의 풀-프레임워크입니다. 라우팅, 상태 관리, HTTP 클라이언트, 폼 처리까지 모든 것을 내장하여 대규모 엔터프라이즈 앱 개발에 최적화되어 있습니다.
Angular의 핵심 철학
React나 Vue와 달리 Angular는 Opinionated Full Framework입니다. 구조와 패턴이 명확하게 정해져 있어 팀 규모가 커도 일관된 코드 스타일을 유지할 수 있습니다.
- TypeScript 네이티브: 타입 안전성과 IDE 지원
- 의존성 주입(DI): 테스트 용이성과 모듈화
- RxJS 통합: 비동기 데이터 스트림 처리
- SSR 지원: Angular Universal로 서버사이드 렌더링
컴포넌트(Component)
Angular 앱의 기본 빌딩 블록입니다. 템플릿, 스타일, 로직을 하나의 단위로 캡슐화합니다.
import { Component, signal, computed } from '@angular/core';
@Component({
selector: 'app-counter',
standalone: true,
template: `
<div class="counter">
<p>현재 카운트: {{ count() }}</p>
<p>2배: {{ doubled() }}</p>
<button (click)="increment()">+1</button>
<button (click)="decrement()">-1</button>
</div>
`,
})
export class CounterComponent {
count = signal(0); // 반응형 신호(Signal)
doubled = computed(() => this.count() * 2); // 파생 상태
increment() { this.count.update(v => v + 1); }
decrement() { this.count.update(v => v - 1); }
}
의존성 주입(Dependency Injection)
Angular의 DI 시스템은 서비스의 인스턴스를 컴포넌트에 자동으로 제공합니다. 테스트 시 모의 객체로 손쉽게 교체할 수 있어 단위 테스트가 매우 용이합니다.
import { Injectable, inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
@Injectable({ providedIn: 'root' }) // 앱 전체에서 싱글턴
export class PostService {
private readonly http = inject(HttpClient);
getPosts(): Observable<Post[]> {
return this.http.get<Post[]>('/api/posts');
}
}
// 컴포넌트에서 inject()로 사용
@Component({ ... })
export class PostListComponent {
private readonly postService = inject(PostService);
posts = signal<Post[]>([]);
ngOnInit() {
this.postService.getPosts().subscribe(posts => this.posts.set(posts));
}
}
RxJS와 반응형 프로그래밍
Angular는 비동기 처리를 위해 RxJS Observable을 적극 활용합니다. 여러 비동기 스트림을 선언적으로 조합하는 강력한 패턴을 제공합니다.
import { combineLatest } from 'rxjs';
import { map, debounceTime, switchMap } from 'rxjs/operators';
// 검색어와 필터 조건이 변경될 때마다 자동으로 API 호출
combineLatest([searchQuery$, filterCategory$])
.pipe(
debounceTime(300), // 타이핑 중 불필요한 요청 방지
switchMap(([query, category]) =>
this.postService.search(query, category) // 이전 요청 자동 취소
),
map(results => results.filter(p => p.published))
)
.subscribe(posts => this.posts.set(posts));
SSR과 점진적 하이드레이션
Angular 17+부터 provideClientHydration(withEventReplay())를 통해 서버에서 렌더링된 HTML을 클라이언트에서 재활용합니다. 이를 통해 FCP(First Contentful Paint)를 크게 향상시킬 수 있습니다.
// app.config.ts
export const appConfig: ApplicationConfig = {
providers: [
provideRouter(routes),
provideHttpClient(withFetch()),
provideClientHydration(withEventReplay()), // 점진적 하이드레이션
],
};