본문 바로가기

개발 공부/Angular

Angular Subject, BehaviorSubject

Angular에서 상태 공유나 이벤트 전달을 위해 RxJS의 Subject 계열을 자주 사용합니다.

그중에서도 Subject와 BehaviorSubject는 사용 빈도가 높지만, 동작 방식이 미묘하게 달라서 쓰는 목적에 맞게 선택해야 합니다.

 

 

Subject: 과거는 필요 없고 지금부터가 중요

Subject는 가장 기본적인 RxJS의 멀티캐스트 스트림입니다.

  • 멀티캐스트 가능한 Observable
  • subscribe() 하기 전까지는 값을 받을 수 없음
  • 마지막 값을 저장하지 않음
import { Subject } from 'rxjs';

const subject = new Subject<number>();

subject.next(1); // 구독자 없음 → 아무 일도 일어나지 않음

subject.subscribe(value => console.log('구독자1:', value));

subject.next(2); // 구독자1: 2

 

  • Subject는 구독자가 생기기 전의 값은 전달하지 않아요.
  • 즉, 과거 값이 필요한 상황에서는 적합하지 않습니다.

 

 


 

 

BehaviorSubject: 항상 마지막 값을 기억해요

BehaviorSubject는 Subject를 확장한 형태로, 항상 가장 최신 값을 기억하고, 새로 구독한 구독자에게도 그 값을 즉시 전달합니다.

 

  • Subject를 확장한 것
  • 초기값 필수
  • 항상 가장 최근 값을 저장하고, 신규 구독자에게 마지막 값 자동 전송
const behavior = new BehaviorSubject<number>(0); // 초기값 0

behavior.next(1); // 값 변경

behavior.subscribe(val => console.log('구독자1:', val)); // 구독자1: 1

behavior.next(2); // 구독자1: 2

 

  • 새로운 구독자라도 항상 가장 최신 값을 받을 수 있음

 

차이점

항목 Subject BehaviorSubject
초기값 없음 필수
최근 값 저장 안함 저장함
신규 구독자 과거 값 못 받음 최신 값 즉시 수신
주로 쓰는 곳 이벤트 스트림 상태 공유 (유저 상태, 폼 등)

 


 

언제 어떤 걸 써야 할까?

 

상황 추천 객체 이유
버튼 클릭, 마우스 이벤트 Subject 이벤트는 현재만 중요함
로그인 사용자 정보, 설정값 유지 BehaviorSubject 새로운 컴포넌트도 최신 상태 필요
라우팅된 페이지마다 상태 공유 BehaviorSubject 상태를 기억하고 유지해야 함
 

 


예시: 사용자 로그인 상태 관리

user.service.ts

@Injectable({ providedIn: 'root' })
export class UserService {
  private userSubject = new BehaviorSubject<User | null>(null);

  get user$(): Observable<User | null> {
    return this.userSubject.asObservable();
  }

  login(user: User) {
    this.userSubject.next(user);
  }

  logout() {
    this.userSubject.next(null);
  }
}

 

header.component.ts

export class HeaderComponent implements OnInit {
  user$ = this.userService.user$;

  constructor(private userService: UserService) {}

  ngOnInit() {
    this.user$.subscribe(user => {
      console.log('로그인된 사용자:', user);
    });
  }
}
 
  • BehaviorSubject 덕분에 컴포넌트가 중간에 구독하더라도 상태를 놓치지 않습니다.