Angular 17 이후, Signals는 프레임워크의 핵심적인 반응성(Reactivity) 모델로 자리 잡았습니다. 많은 개발자들이 "RxJS보다 쉽다"는 첫인상을 받지만, 실제 프로젝트에 적용하다 보면 예상치 못한 동작에 당황하는 경우가 많습니다. 바로 기존의 반응형 프로그래밍(RxJS 등)과 다른 작동 원리 때문입니다.
이번 글에서는 개발자들이 가장 흔하게 겪는 혼란의 원인을 분석하고, Signals의 핵심 작동 원리를 파헤쳐 올바른 사용법을 알아보겠습니다.
우리가 마주한 상황은 이렇습니다. 컴포넌트의 상태를 관리하기 위해 Signal을 선언하고, 특정 로직 안에서 값을 변경했습니다. 하지만 템플릿의 일부는 업데이트되는데, 다른 부분은 아무런 반응이 없습니다.
문제는 Signals를 RxJS의 Observable이나 일반 변수의 연장선으로 생각하는 기존의 사고방식에 있습니다.
이 근본적인 차이를 인지하지 못하면, 왜 내 코드가 예상대로 동작하지 않는지 이해하기 어렵습니다.
우리의 목표: Signals가 Angular의 변경 감지 시스템과 어떻게 상호작용하는지 이해하고, computed와 effect의 역할을 명확히 구분하여 예측 가능한 코드를 작성하자!
이 문제를 해결하려면 Signals가 단순한 '값'이 아니라 Angular 생태계 안에서 어떻게 작동하는지 이해해야 합니다.
가장 큰 오해 중 하나는 "Signal 값만 바꾸면 Angular가 마법처럼 모든 것을 업데이트해 줄 것"이라는 믿음입니다. 사실 Signals는 Angular의 기존 변경 감지 시스템을 대체하는 것이 아니라, 더 효율적으로 만들어주는 도구입니다.
두 함수를 혼용하는 것은 혼란을 가중시킬 뿐입니다. 역할이 완전히 다릅니다.
Signals는 객체나 배열의 내부 속성이 바뀌는 것을 감지하지 못합니다. 오직 새로운 참조(Reference)로 교체될 때만 변화로 인식합니다.
이 원리는 불변성(Immutability)을 지키는 것이 왜 중요한지 다시 한번 상기시켜 줍니다.
이제 위 원리들을 바탕으로 실제 코드에서 발생하는 흔한 실수들을 살펴보겠습니다.
const todos = signal<string[]>(['공부하기']);
// ❌ 잘못된 방법: Signal이 참조 변경을 감지하지 못함
function addTodoWrong(newTodo: string) {
todos().push(newTodo); // 배열의 내부만 변경, 참조는 그대로
}
// ✅ 올바른 방법: 새로운 배열을 생성하여 참조를 교체
function addTodoRight(newTodo: string) {
todos.update(currentTodos => [...currentTodos, newTodo]);
}
이유: update 콜백에서 스프레드 연산자(...)를 사용해 새로운 배열을 반환했기 때문에, todos Signal은 값이 변경되었음을 인지하고 UI를 업데이트합니다.
const firstName = signal('John');
const lastName = signal('Doe');
let fullName = ''; // 일반 변수
// ❌ 잘못된 방법: fullName은 반응성이 없으며, effect는 값을 반환하지 않음
effect(() => {
fullName = `${firstName()} ${lastName()}`;
console.log('이름이 변경됨:', fullName);
});
// ✅ 올바른 방법: 파생된 상태를 위해 computed 사용
const fullNameSignal = computed(() => `${firstName()} ${lastName()}`);
// 이제 템플릿에서 {{ fullNameSignal() }} 처럼 사용 가능
이유: computed는 fullNameSignal이라는 새로운 반응형 값을 만들어주므로, 템플릿이나 다른 Signal에서 재사용할 수 있습니다. effect는 단순히 특정 동작을 수행할 뿐입니다.
Angular Signals는 RxJS를 대체하기 위한 기술이 아니라, 컴포넌트 상태를 직관적이고 효율적으로 관리하기 위한 새로운 패러다임입니다. 기존의 사고방식을 버리고 Signals의 핵심 원리를 이해하는 것이 중요합니다.
이 방법들을 통해 우리는 Signals를 활용하여 더 예측 가능하고 안정적인 애플리케이션을 구축할 수 있습니다. Signals는 올바른 상황에서 사용한다면 가장 강력한 도구가 될 것입니다.