自 Angular 最新版本以來,在框架內開發了一種新的原始反應系統:訊號!
今天,事後看來,我們意識到某些用例尚未被覆蓋,顯然 Angular 團隊的積極反應將為我們提供幫助來覆蓋這些用例。
這些用例是什麼?將採取哪些解決方案以及如何使用它們?
讓我們先說明這個問題。
假設我們有一籃子一定數量的水果。
數量由輸入水果的組件管理。
@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++); } }
如果輸入的水果價格發生變化,則必須重設變數。
一個簡單的解決方案是使用效果
@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++); } }
前面的程式碼是不好的做法。為什麼這是一個大問題?
我們需要將 signalWrites 選項設為 true 才能設定信號量。這是由於對給定問題的誤解造成的。
在我們的例子中,我們想要同步兩個變量,在我們的具體化中,這兩個變數是不同步的
櫃檯並不獨立於水果,水果是我們最初的來源。實際上,這裡我們有一個組件狀態,其初始來源是水果,其餘部分是水果的衍生物。
具體化問題如下
@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++); } }
這種具體化將水果與其數量緊密聯繫起來。
因此,一旦水果發生變化,計算變數fruitState就會自動重新計算。此重新計算傳回具有數量屬性的對象,該物件是初始化為 1 的訊號。
透過返回訊號,變數可以在點擊時遞增,並在水果變化時簡單地重置。
這是一個相對簡單的設定模式,但我們不能簡化它嗎?
隨著 Angular 19 的到來,一個用於計算派生訊號的新函數。
到目前為止,我們已經有了計算函數,但該函數傳回一個 Signal 而不是 WrittableSignal,這在我們之前的數量變數用例中是實用的。
這就是 LinkedSignal 的用武之地。 LinkedSignal,顧名思義,讓您可以將兩個訊號強連結在一起。
如果我們回到先前的情況,這個函數將允許我們簡化程式碼,如下所示:
@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++); } }
linkedSignal函數定義如下:
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>;
在第一個定義(「縮寫」定義)中,linkedSignal 函數採用計算函數作為參數和配置物件。
@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++); } }
在前面的範例中,由於計算函數取決於數量訊號,因此當數量變化時,計算函數會重新評估。
在第二個定義中,linkedFunction方法將一個物件作為具有三個屬性的參數
與「縮寫」計算函數相反,這裡的計算函數將來源值和「先例」作為參數。
@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 將引入一個新的 API,用於簡單的資料擷取和查詢狀態(待處理等)、資料和錯誤的檢索。
對於那些稍微熟悉框架的人來說,這個新 API 的工作方式有點像 useRessource 鉤子。
讓我們來看一個例子:
@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++); } }
關於此程式碼片段,有幾件事要了解
這段程式碼中有幾點要注意:
以下效果將列印這些值
@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++); } }
如上所述,預設情況下,fruitId 訊號是未追蹤的。
那麼每次這個訊號的值發生變化時如何重新啟動http請求,以及如果fruitId訊號的值發生變化而對上一個請求的回應沒有變化,如何取消上一個請求到了嗎?
資源函數採用另一個名為 request 的屬性。
此屬性將依賴訊號的函數作為其值並傳回其值。
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>;
如上面的程式碼所示,載入器函數有兩個參數
因此,如果在 httpRequest 檢索水果詳細資料期間,fruitId 訊號的值會發生變化,則該請求將被取消以啟動新請求。
最後,Angular 也想到了將這個新 api 與 RxJs 耦合的可能性,讓我們能夠從 Rx 運算子的強大功能中受益。
互通性是透過 rxResource 函數實現的,它的定義方式與資源函數完全相同。
唯一的差異是 loader 屬性的回傳類型,它將傳回一個 observable
@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++); } }
這裡不需要abortSignal,當訊號fruitId的值改變時取消先前的請求,隱含在函數rxResource中,行為與switchMap運算子相同。
以上是Angular 反應性的下一個改進的詳細內容。更多資訊請關注PHP中文網其他相關文章!