Heim >Web-Frontend >js-Tutorial >Die nächste Verbesserung der Winkelreaktivität
Seit den neuesten Versionen von Angular wurde innerhalb des Frameworks ein neues primitives Reaktivitätssystem entwickelt: Signale!
Heute stellen wir im Nachhinein fest, dass bestimmte Anwendungsfälle nicht abgedeckt wurden, und offensichtlich wird uns das Angular-Team, das sehr reaktiv ist, Helfer zur Verfügung stellen, um diese Anwendungsfälle abzudecken.
Was sind diese Anwendungsfälle? Welche Lösungen werden eingeführt und wie werden sie genutzt?
Beginnen wir mit der Veranschaulichung dieses Problems.
Stellen wir uns vor, wir haben einen Obstkorb mit einer bestimmten Menge.
Die Menge wird durch eine Komponente verwaltet, die die Frucht eingibt.
@Component({ template: `<button type="button" (click)="updateQuantity()"> {{quantity()}} </button>` }) export class QuantityComponent() { fruit = input.required<string>(); count = signal(1); updateQuantity(): void { this.count.update(prevCount => prevCount++); } }
Hier muss die Variable zurückgesetzt werden, wenn sich der Eingabepreis Obst ändert.
Eine einfache Lösung wäre die Verwendung eines Effekts
@Component({ template: `<button type="button" (click)="updateQuantity()"> {{quantity()}} </button>` }) export class QuantityComponent() { fruit = input.required<string>(); quantity = signal(1); countEffect(() => { this.fruit(); this.quantity.set(1); }, { allowSignalWrites: true }) updateQuantity(): void { this.quantity.update(prevCount => prevCount++); } }
Der vorstehende Code ist eine schlechte Praxis. Warum ist das die große Frage?
Wir müssen die Option signalWrites auf true setzen, um die Signalmenge festzulegen. Dies liegt an einer Fehlinterpretation des gegebenen Problems.
In unserem Fall möchten wir zwei Variablen synchronisieren, die in unserer Materialisierung desynchronisiert sind
Der Zähler ist nicht unabhängig von der Frucht, die unsere Ausgangsquelle ist. In Wirklichkeit haben wir hier einen Komponentenzustand, dessen ursprüngliche Quelle die Frucht ist und der Rest ein Derivat der Frucht ist.
Materialisieren Sie das Problem wie folgt
@Component({ template: `<button type="button" (click)="updateQuantity()"> {{fruitState().quantity()}} </button>` }) export class QuantityComponent() { fruit = input.required<string>(); fruitState = computed(() => ({ source: fruit(), quantity: signal(1), })); updateQuantity(): void { this.fruitState().quantity.update(prevCount => prevCount++); } }
Diese Materialisierung verknüpft die Frucht stark mit ihrer Menge.
Sobald sich also die Frucht ändert, wird die berechnete Variable FruitState automatisch neu berechnet. Diese Neuberechnung gibt ein Objekt mit der Mengeneigenschaft zurück, bei dem es sich um ein auf 1 initialisiertes Signal handelt.
Durch die Rückgabe eines Signals kann die Variable bei einem Klick erhöht und einfach zurückgesetzt werden, wenn sich die Frucht ändert.
Es ist ein relativ einfaches Muster einzurichten, aber können wir es nicht vereinfachen?
Mit der Einführung von Angular 19 eine neue Funktion zur Berechnung abgeleiteter Signale.
Bisher hatten wir die berechnete Funktion, aber diese Funktion gibt ein Signal und kein WrittableSignal zurück, was in unserem vorherigen Anwendungsfall für die Mengenvariable praktisch gewesen wäre.
Hier kommt LinkedSignal ins Spiel. LinkedSignal ermöglicht Ihnen, wie der Name schon sagt, die starke Verknüpfung zweier Signale miteinander.
Wenn wir zu unserem vorherigen Fall zurückkehren, würde uns diese Funktion ermöglichen, den Code wie folgt zu vereinfachen:
@Component({ template: `<button type="button" (click)="updateQuantity()"> {{quantity()}} </button>` }) export class QuantityComponent() { fruit = input.required<string>(); quantity = linkedSignal({ source: fruit, computation: () => 1 }); updateQuantity(): void { this.quantity.update(prevCount => prevCount++); } }
Die LinkedInedSignal-Funktion ist wie folgt definiert:
linkedSignal(computation: () => D, options?: { equal?: ValueEqualityFn<NoInfer<D>>; }): WritableSignal<D>; linkedSignal(options: { source: () => S; computation: (source: NoInfer<S>, previous?: { source: NoInfer<S>; value: NoInfer<D>; }) => D; equal?: ValueEqualityFn<NoInfer<D>>; }): WritableSignal<D>;
In der ersten Definition, der „abgekürzten“ Definition, akzeptiert die Funktion „linkedSignal“ eine Berechnungsfunktion als Parameter und ein Konfigurationsobjekt.
@Component({ template: `<button type="button" (click)="updateQuantity()"> {{quantity()}} </button>` }) export class QuantityComponent() { fruit = input.required<string>(); count = signal(1); updateQuantity(): void { this.count.update(prevCount => prevCount++); } }
Da in diesem vorherigen Beispiel die Berechnungsfunktion vom Mengensignal abhängt, wird die Berechnungsfunktion bei einer Mengenänderung neu bewertet.
In der zweiten Definition akzeptiert die LinkedInFunction-Methode ein Objekt als Parameter mit drei Eigenschaften
Im Gegensatz zur „abgekürzten“ Berechnungsfunktion verwendet die Berechnungsfunktion hier als Parameter den Wert der Quelle und einen „Präzedenzfall“.
@Component({ template: `<button type="button" (click)="updateQuantity()"> {{quantity()}} </button>` }) export class QuantityComponent() { fruit = input.required<string>(); quantity = signal(1); countEffect(() => { this.fruit(); this.quantity.set(1); }, { allowSignalWrites: true }) updateQuantity(): void { this.quantity.update(prevCount => prevCount++); } }
Angular 19 wird eine neue API für den einfachen Datenabruf und den Abfragestatus (ausstehend usw.), Daten und Fehler einführen.
Für diejenigen, die mit dem Framework ein wenig vertraut sind: Diese neue API funktioniert ein bisschen wie der useRessource-Hook.
Schauen wir uns ein Beispiel an:
@Component({ template: `<button type="button" (click)="updateQuantity()"> {{fruitState().quantity()}} </button>` }) export class QuantityComponent() { fruit = input.required<string>(); fruitState = computed(() => ({ source: fruit(), quantity: signal(1), })); updateQuantity(): void { this.fruitState().quantity.update(prevCount => prevCount++); } }
Über dieses Code-Snippet gibt es einiges zu wissen
In diesem Snippet-Code sind mehrere Dinge zu beachten:
Der folgende Effekt druckt diesen Wert
@Component({ template: `<button type="button" (click)="updateQuantity()"> {{quantity()}} </button>` }) export class QuantityComponent() { fruit = input.required<string>(); quantity = linkedSignal({ source: fruit, computation: () => 1 }); updateQuantity(): void { this.quantity.update(prevCount => prevCount++); } }
Wie oben erläutert, wird das FruitId-Signal standardmäßig nicht verfolgt.
Wie starten Sie also die HTTP-Anfrage jedes Mal neu, wenn sich der Wert dieses Signals ändert, aber wie brechen Sie auch die vorherige Anfrage ab, falls sich der Wert des FruitId-Signals ändert, die Antwort auf die vorherige Anfrage jedoch nicht ankommen?
Die Ressourcenfunktion benötigt eine weitere Eigenschaft namens „request“.
Diese Eigenschaft nimmt als Wert eine Funktion an, die von Signalen abhängt und deren Wert zurückgibt.
linkedSignal(computation: () => D, options?: { equal?: ValueEqualityFn<NoInfer<D>>; }): WritableSignal<D>; linkedSignal(options: { source: () => S; computation: (source: NoInfer<S>, previous?: { source: NoInfer<S>; value: NoInfer<D>; }) => D; equal?: ValueEqualityFn<NoInfer<D>>; }): WritableSignal<D>;
Wie im obigen Code gezeigt, benötigt die Loader-Funktion zwei Parameter
Wenn sich also der Wert des FruitId-Signals während einer httpRequest ändert, die die Details einer Frucht abruft, wird die Anfrage abgebrochen, um eine neue Anfrage zu starten.
Schließlich hat Angular auch über die Möglichkeit nachgedacht, diese neue API mit RxJs zu koppeln, sodass wir von der Leistungsfähigkeit der Rx-Operatoren profitieren können.
Interporabilität wird mithilfe der rxResource-Funktion erreicht, die genauso definiert ist wie die Ressourcenfunktion.
Der einzige Unterschied besteht im Rückgabetyp der Loader-Eigenschaft, die ein Observable
zurückgibt
@Component({ template: `<button type="button" (click)="updateQuantity()"> {{quantity()}} </button>` }) export class QuantityComponent() { fruit = input.required<string>(); count = signal(1); updateQuantity(): void { this.count.update(prevCount => prevCount++); } }
Hier ist es nicht notwendig, das abortSignal zu haben, das Abbrechen der vorherigen Anfrage, wenn sich der Wert des Signals FruitId ändert, ist implizit in der Funktion rxResource und das Verhalten ist das gleiche wie beim switchMap-Operator.
Das obige ist der detaillierte Inhalt vonDie nächste Verbesserung der Winkelreaktivität. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!