computed()
computed()는 하나 이상의 signal() 값에 의존하여 계산된 값을 자동으로 업데이트해주는 함수입니다.
computed()는 파생된 상태를 선언적으로 정의할 수 있는 핵심 도구로, 코드의 복잡도를 낮추고 예측 가능성을 높여줍니다.
const count = signal(2);
const doubled = computed(() => count() * 2);
console.log(doubled()); // 4
count.set(4);
console.log(doubled()); // 8 (자동 업데이트)
- count라는 상태가 바뀔 때마다 doubled라는 값이 자동으로 다시 계산된다는 걸 보여줍니다.
왜 computed()를 쓰는가?
get currentTabKey() {
return this.tabList()[this.currentTabIndex()].key;
}
- 이것도 동작하지만, getter는 호출될 때마다 무조건 계산을 다시 합니다.
- 반면 computed()는 의존한 signal이 바뀌지 않으면 캐싱된 값을 반환하기 때문에 성능 측면에서 효율적입니다.
| 항목 | getter | computed() |
| 호출 시 무조건 계산 | O | X(변화 있을 때만) |
| 반응형 연결 | X | O |
| 템플릿에서 직접 사용 | 계산만 가능 | signal로 연결 가능 |
구성 요소 비교
| 구분 | 역할 | 예시 |
| signal() | 상태 저장 | const count = signal(1); |
| computed() | 상태를 기반으로 파생된 값 계산 | const double = computed(() => count() * 2); |
| effect() | signal 또는 computed가 바뀔 때 부수효과 실행 | effect(() => console.log(count())); |
예제: 탭 키 동기화
컴포넌트에 여러 탭이 있다고 해볼게요. 우리는 선택된 탭의 key 값을 계산해서 어딘가에 표시하거나 로직에 활용하고 싶습니다.
이걸 RxJS로 하면 BehaviorSubject랑 combineLatest 같은 걸 써야 했지만, Signal을 사용하면 이렇게 간단하게 처리됩니다
export class TabComponent {
// 탭 리스트
tabList = signal([
{ key: 'home' },
{ key: 'settings' },
{ key: 'profile' }
]);
// 현재 탭 인덱스
currentTabIndex = signal(0);
// 현재 탭의 key를 자동으로 계산
public currentTabKey: Signal<string> = computed(() => {
return this.tabList()[this.currentTabIndex()].key;
});
// 탭 변경 메서드
nextTab() {
const next = (this.currentTabIndex() + 1) % this.tabList().length;
this.currentTabIndex.set(next);
}
}
HTML 템플릿
<p>현재 탭 키: {{ currentTabKey() }}</p>
<button (click)="nextTab()">다음 탭</button>
- currentTabKey는 signal이기 때문에, currentTabKey() 처럼 함수처럼 호출해서 값을 읽습니다.
실수하는 패턴
아래처럼 사용하는 건 권장되지 않습니다
const wrong = signal(computed(() => count() * 2)); // 의미 없음
- 이렇게 되면 wrong()을 호출하면 Signal<number> 객체가 나오고, 실제 값은 wrong()()처럼 이중 호출해야 얻을 수 있어서 매우 비직관적입니다.
'개발 공부 > Angular' 카테고리의 다른 글
| RxJS 연산자 debounceTime, switchMap, mergeMap (1) | 2025.05.29 |
|---|---|
| 컴포넌트 인클루전 방식 vs 라우트 분리 방식 (0) | 2025.05.27 |
| @HostListener (0) | 2025.05.19 |
| Angular Directive (0) | 2025.05.17 |
| Angular Route Guard (canActivateChild, canDeactivate, canLoad ) (0) | 2025.03.17 |