การแปลงสิ่งที่สังเกตได้เป็นสัญญาณในเชิงมุม: สิ่งที่คุณต้องรู้

May 01 2023
Angular v16 มาพร้อมกับแพ็คเกจใหม่ชื่อ rxjs-interop ซึ่งแนะนำฟังก์ชัน toSignal ที่แปลงสัญญาณที่สังเกตได้ไปเป็นสัญญาณ ในบทความนี้ เราจะพิจารณาคุณลักษณะใหม่นี้และการใช้งานอย่างละเอียดยิ่งขึ้น

Angular v16 มาพร้อมกับแพ็คเกจใหม่ชื่อ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ฟังก์ชันจะสมัครรับข้อมูลที่สังเกตได้ในทันทีซึ่งอาจทำให้เกิดผลลัพธ์ที่ไม่ต้องการในบางกรณีหากมีผลข้างเคียง

หากเรามีโค้ดที่ใช้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ที่สังเกตได้ซึ่งไม่เริ่มทำงานในทันที

@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การเรียกใช้ฟังก์ชัน ขั้นแรกจะตรวจสอบ เพื่อให้แน่ใจว่า ฟังก์ชันนั้นถูกเรียกในบริบทการฉีด ถ้าไม่เช่นนั้นจะเกิดข้อผิดพลาดขึ้น นั่นหมายความว่าเราจะใช้toSignalฟังก์ชันได้ก็ต่อเมื่อinject() ฟังก์ชันนั้นพร้อมใช้งาน ยกเว้นกรณีที่เราใช้manualCleanupตัวเลือกหรือส่งผ่านinjectorอย่างชัดเจน

เหตุผลนี้คือ Angular จะยกเลิกการสมัครโดยอัตโนมัติเมื่อบริบทการห่อถูกทำลาย ทำสิ่งนี้โดยใช้OnDestroyhook ใหม่ที่ได้รับจากการใช้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);
    }
  }
}

ติดตามฉันบนMediumหรือTwitterเพื่ออ่านเพิ่มเติมเกี่ยวกับ Angular และ JS!