>  기사  >  웹 프론트엔드  >  신호를 사용하여 Angular 구성 요소를 구성하는 방법

신호를 사용하여 Angular 구성 요소를 구성하는 방법

Patricia Arquette
Patricia Arquette원래의
2024-10-09 06:23:29585검색

How I structure my Angular components with Signals

이 짧은 기사에서는 외부 라이브러리 없이 신호를 사용하여 구성 요소를 구성하는 방법을 보여 드리고 싶습니다. 물론 NgRx와 같은 것들이 우리 코드를 더욱 강력하게 만드는 데 큰 역할을 하겠지만, 간단하게 시작해 보겠습니다!

우선 모든 상태를 신호로 정의합니다.

export class TodoListComponent {
  todos = signal<Todo[]>([]);
}

입력에도 동일하게 적용됩니다! 내 구성 요소에 입력이 필요한 경우 Angular의 새로운 input() 함수를 사용하여 이를 선언하면 신호도 제공됩니다. 그리고 경로 매개변수인 경우 input.required()를 사용합니다.

그런 다음 다른 상태에서 파생될 수 있는 상태를 표시하려면 항상 계산을 사용합니다.

completedTodos = computed(() => this.todos().filter(t => t.completed));

그렇다면 저를 아시는 분이라면 제가 클래스 메서드 내에서 직접 비동기 부작용을 수행하는 것을 얼마나 경멸하는지 아실 겁니다... ?

export class TodoListComponent {
  todoService = inject(TodoService);

  toggleTodo(id: string) {
    this.todoService.toggle(id).subscribe(newTodo => ...);
  }
}

왜 물어보나요? 메서드가 부작용(이 경우 구독 호출)을 직접 시작하는 메서드라면 백 프레셔를 제어할 수 없습니다.

백 프레셔는 다음과 같이 요약할 수 있습니다. 이전 호출이 완료되지 않은 상태에서 사용자가 할 일을 전환하면 어떻게 되나요?

다음과 같은 여러 가지 문제가 있습니다.

  1. 두 번째 통화를 하시겠습니까? 아니면 첫 번째 작업이 완료될 때까지 기다리시나요? 아니면 첫 번째를 취소해야 할까요?
  2. 짧은 시간에 다양한 아이템을 전환하면 어떨까요?
  3. 일종의 디바운스 또는 스로틀을 도입하고 싶다면 어떻게 해야 할까요?

RxJS를 알고 계시다면(이 글을 읽고 계시다면 지금쯤은 아실 겁니다!) 첫 번째 문제는 4가지 평면화 연산자(mergeMap, concatMap, switchMap, 배기 맵)를 사용하면 쉽게 해결된다는 것을 아실 것입니다.

그렇다면 RxJS를 꽤 잘 아시는 분이라면 groupBy라는 멋진 연산자로 두 번째 문제를 해결할 수 있다는 사실을 아실 겁니다!

하지만 이 장점을 모두 활용하려면 Observable 소스가 있어야 하므로 메소드가 아닙니다.

과목

주제를 열려 있고(완료되지 않음) 비어 있는 Observable이라고 생각하세요. 맞춤 이벤트를 표현하는 완벽한 도구입니다.

구성요소의 모든 이벤트는 제목으로 표시될 수 있습니다.

export class TodoListComponent {
  ...

  toggleTodo$ = new Subject<string>();
  deleteTodo$ = new Subject<string>();
  addTodo$ = new Subject<void>();
}

그런 다음 템플릿은 메서드를 호출하는 대신 필요할 때 간단히 호출할 수 있습니다. 예를 들면 다음과 같습니다.

<button (click)="deleteTodo$.next(todo.id)">delete</button>

이제 소스가 Observable이므로 연산자를 사용할 수 있습니다. 효과를 만들어 보겠습니다.

효과

저는 구성 요소가 소멸될 때 takeUntilDestroyed() 연산자를 사용하여 효과를 정리할 수 있도록 생성자 내부에 효과를 정의하는 것을 좋아합니다! 예를 들면 다음과 같습니다.

constructor() {
  this.addTodo$.pipe(
    concatMap(() => this.todoService.add())
    takeUntilDestroyed()
  ).subscribe(newTodo => this.todos.update(todos => [...todos, newTodo]));
}

여기에서는 응답 순서를 유지하여 할 일이 순서대로 추가되도록 concatMap을 사용합니다. 이는 동시 호출이 없음을 의미합니다. 추가 작업에는 완벽하다고 생각하지만 다른 호출에는 잘못된 선택일 수 있습니다. 예를 들어 GET 요청의 경우 사용 사례에 따라 일반적으로 배기 맵 또는 스위치 맵을 사용하는 것이 더 좋습니다.

또한 비관적 업데이트라는 접근 방식을 사용하고 있는데, 이는 내부 상태를 업데이트하기 위해 호출이 끝날 때까지 기다린다는 의미입니다. 이건 개인취향이에요! 즉시 할일을 추가한 다음, API 호출에 오류가 발생하면 catchError를 사용하여 되돌릴 수 있습니다.

그리고 신호와 함께 사용하기 위한 Angular의 실제 효과 기능이 있습니다. 저는 이 기능을 동기화 작업에 사용합니다. 예를 들어 URL에서 매개변수가 변경되면(새 엔터티 ID 참조) 새 엔터티로 양식을 업데이트할 수 있습니다.

// This comes from the router
id = input.required<string>();

// Always stores the current invoice information
currentInvoice = toSignal(toObservable(this.id).pipe(
  switchMap(id => this.invoiceService.get(id))
));

constructor() {
  effect(() => {
    // Assuming the 2 structures match, every time we browse
    // to a new invoice, the form gets populated
    this.form.patchValue(this.currentInvoice());
  })
}

이 기술로는 배압을 제어할 수 없습니다. 이런 종류의 경우에는 괜찮지만 이것이 버그 없는 앱을 만들기 위해 여전히 RxJS가 필요한 이유라는 점을 기억하세요. 또는 이러한 복잡성을 내부적으로 추상화하는 또 다른 라이브러리입니다.

완전한 리액티브로 가는 것이 항상 좋은 생각은 아닙니다.

우리가 신호로 표현하는 많은 상태는 기술적으로 파생된 비동기 상태로 간주될 수 있습니다. 예를 들어 Todo 목록은 서버에서 파생된 상태로 간주될 수 있습니다.

// Trigger this when you need to refetch the todos
fetchTodos$ = new Subject<void>();

todos = toSignal(toObservable(this.fetchTodos$).pipe(
  switchMap(id => this.todoService.getAll())
));

이 접근 방식은 새 데이터가 필요할 때 쿼리를 수동으로 무효화하는 TanStack Query와 같은 라이브러리에서 사용하는 접근 방식과 유사합니다. 즉, 변이마다 항상 서버로 이동하게 됩니다.

일부 시나리오에서는 이것이 좋을 수도 있지만 고려해야 할 두 가지 사항이 있습니다.

  1. 상태를 수동으로 업데이트(낙관적 업데이트)하기가 어렵습니다. TanStack Query와 같은 라이브러리를 사용하면 이 작업이 더 쉬워지지만 수동으로 수행하는 것은 번거롭습니다.
  2. 대부분의 개발자가 코드를 파악하기가 다소 더 어렵습니다. 매일 이런 종류의 작업을 수행하는 컨설턴트로서 이것이 바로 제가 보는 것입니다.

요컨대 보통은 추천하지 않습니다. 그리고 저는 보통이라고 했어요! :)

결론

이 짧은 기사가 마음에 드셨기를 바랍니다! 요약하자면:

  • 상태를 신호로 정의
  • 파생된 상태를 계산된 신호로 정의
  • 비동기 효과를 Observable로 정의하세요
  • 효과로 동기화 효과 정의

이러한 원칙을 따르면 앱을 유지 관리하기가 훨씬 쉬워질 것이라고 확신합니다!

위 내용은 신호를 사용하여 Angular 구성 요소를 구성하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.