Observable을 Angular의 신호로 변환: 알아야 할 사항

May 01 2023
Angular v16에는 observable을 신호로 변환하는 toSignal 함수를 도입하는 rxjs-interop이라는 새 패키지가 함께 제공됩니다. 이 기사에서는 이 새로운 기능과 사용법에 대해 자세히 살펴보겠습니다.

Angular v16 에는 Observable을 신호로 변환하는 기능을 rxjs-interop소개하는 이라는 새 패키지가 함께 제공됩니다 . toSignal이 기사에서는 이 새로운 기능과 사용법에 대해 자세히 살펴보겠습니다.

함수 사용을 시작하려면 모듈 toSignal에서 함수를 가져와야 합니다 @angular/core/rxjs-interop. 다음은 사용법을 보여주는 예제 코드 스니펫입니다.

import { toSignal } from '@angular/core/rxjs-interop';
import { interval } from 'rxjs';

@Component({
  standalone: true,
  template:`{{ counter() }}`,
})
export class FooComponent {
  counter$ = interval(1000);
  counter = toSignal(this.counter$);
}

async파이프와 달리 구성 요소에서 즉시 신호 값을 읽을 수 있다는 점은 주목할 가치가 있습니다 undefined.

게다가 이 toSignal함수는 observable을 즉시 구독하므로 부작용이 있는 경우 경우에 따라 원치 않는 결과가 발생할 수 있습니다.

async지시문 과 함께 파이프를 사용하는 코드가 있는 경우 ngIf템플릿을 렌더링할 때만 관찰 가능 항목을 구독합니다.

@Component({
  standalone: true,
  template:`<div *ngIf="someCondition">
     <div *ngFor="let item of source$ | async"></div>
  </div>`,
})
export class FooComponent {
  source$ = inject(Service).someMethod();
}

결과 신호에서 유형 을 제거하려는 경우 undefined두 가지 옵션이 있습니다. async첫 번째는 즉시 실행되지 않는 observable이 있을 때 초기 값을 전달하는 것입니다 .

@Component({
  standalone: true,
  template:`{{ counter() }}`,
})
export class FooComponent {
  counter$ = interval(1000);
  counter = toSignal(this.counter$, { initialValue: 0 });
}

@Component({
  standalone: true,
  template:`{{ counter() }}`,
})
export class FooComponent {
  counter$ = interval(1000).pipe(startWith(0));
  counter = toSignal(this.counter$, { requireSync: true });
}

toSignal함수가 호출 되면 먼저 주입 컨텍스트 에서 호출되고 있는지 확인 합니다 . 그렇지 않으면 오류가 발생합니다. 즉, 옵션을 사용하거나 명시적으로 전달하는 경우를 제외하고 함수를 사용할 수 있는 경우에만 함수를 사용할 수 있습니다 .toSignalinject() manualCleanupinjector

그 이유는 래핑 컨텍스트가 소멸되면 Angular가 자동으로 구독을 취소 하기 때문입니다. 함수 또는 명시적으로 제공된 다음을 사용하여 OnDestroy얻은 새 후크를 사용하여 이를 수행합니다 .inject()injector

@Component({
  selector: 'foo',
  standalone: true,
  template:`{{ counter() }}`,
})
export class FooComponent {
  counter$ = interval(1000);
  counter: Signal<number | undefined>; 
  private injector = inject(Injector);

  ngOnInit() {
    this.counter = toSignal(this.counter$, { injector: this.injector } );
  }
}

@Component({
  standalone: true,
  template:`{{ counter() }}`,
})
export class FooComponent {
  counter$ = interval(1000).pipe(take(3));
  counter = toSignal(this.counter$, { manualCleanup: true });
}

@Component({
  standalone: true,
  template:`{{ counter() }}`,
})
export class FooComponent {
  counter$ = interval(1000);
  counter = toSignal(this.counter$, { initialValue: 0 });

  ngOnInit() {
    try {
      this.counter();
    } catch (e) {
      console.log(e);
    }
  }
}

Angular 및 JS에 대해 자세히 알아보려면 Medium 또는 Twitter 에서 저를 팔로우하세요 !