Signals Angular zone.js change detection WritableSignal

Angular Signals 是甚麼? 一篇文章讓你清楚前因後果

劉晏瑞 Ray Liu 2025/01/22 20:08:42
18

開始之前

Angular 從v16推出 dev-preview 到 v17的穩定版的新功能 - Signals , computed() 還有 effect()。為Angular的變更機制投下震撼彈,本篇文章帶你快速實戰,並解釋功能的來龍去脈。

 

Signals

counter = signal(0);

沒錯,定義一個signal就是這麼簡單

更嚴謹的寫法可以透過泛型將資料類別傳進去,回傳的型別跟上面一樣是WritableSignal

counter: WritableSignal<number> = signal<number>(0);

 

Signal() 及 Signal.set()

這次我們使用一個常見的範例 "計數器"

透過呼叫 add() function 將計數器加一,並將資料顯示在畫面上

add(): void {
  this.counter.set(this.counter() + 1);
}
count {{ counter() }}
<button (click)="add()"> Add 1 </button>  

 

另外,除了 Signal.set(),也可以透過 Signal.update() api 將更新資料

若將 add() function 改寫成 update 方式更新的程式碼如

add(): void {
  this.counter.update((count) => count + 1);
}

 

computed() 及 effect()

延續範例

假設計數的是商品數量,可以透過 computed() 將數量計算為總金額

並在數量增加時,同步更新金額到畫面上

total = computed(() => this.counter()*1980);

值得注意的是,computed 產生的 total 是 Readonly 的 Signal

更新機制跟隨 this.counter signal 改變

<div> 總金額:${{ total() }} </div>

也可以透過 effect() 在商品增加時觸發其他事件

constructor() {
...
  effect(() => console.log(`商品已加入,目前數量${this.counter}`));
...
}

因為 DI 的原故, effect() 需要寫在建構子內,否則Angular會提示錯誤

 

 

asReadonly()

Signal 大致分為 Writable 以及 Readonly(也就是Signal type) writable 是不管從何存取,都可以任意更改資料。

實際使用像是透過 service 存取資料時,我們可以將signal資料透過 asReadonly api 提供給其他程式,保持寫入資料的控管。

getCountSignal(): Signal<number> {
  return this.counter.asReadonly();
}

 

 

結束了...嗎?

以上就是 Signals 相關的功能與簡單實作範例,是不是很簡單呢?

透過 signal() 建立實體,並呼叫 .set() 或 .update() 更新內容,取代舊有的 data-binding 方式以更可控的方式控制資料流

不過仔細想想,好像哪邊怪怪的...

 

「難道原本 data-binding 寫法不香嗎?」

過去的版本,Angular 仰賴 NgZone (zone.js) 管控網頁的變更機制

在事件觸發後 NgZone 首先將事件攔截,並嘗試偵測相關資料是否變更,最後重新渲染畫面。整套流程下來事件的目的達到了,但影響的範圍可能過多

 

另外對開發者而言從 "事件觸發" 到 "畫面渲染" 在舊有版本中,Angular 透過 NgZone 機制,將流程包在語法糖裡。

開發者通常只知道 「資料變更,畫面就會自動渲染了」,而對於極少數,資料有變更畫面卻沒有重新渲染的情形,常常會不知所云

這種情形的解法通常是把元件改成 pure component ,並以手動的方式觸發變更機制。

 

 

Signal 以及 OnPush

針對改善變更機制效能的新解方,如果放在 ChangeDetectionStrategy.OnPush 的元件內,Signal 的內容更新依然需要手動觸發嗎?

答案是: 不需要。

在啟用 OnPush 的元件內,所有的 Signal 或延伸的 ReadOnly Signal 皆會自動更新,畢竟兩種的觸發監控機制已經不同了。

 

 

總結與心得

Signal 提供一種能更完善管控資料流,並將變更機制侷限在範圍內的機制

雖然寫起來比舊版本的方式麻煩,但對於改善效能與減少資源浪費的課題,不乏是一個好的解決方案

 

 

資料與參考來源:

Angular v19 Signal 官方文件

Angular v19 ChangeDetectorRef官方文件

全端開發人員天梯

 

作者:

RayLiu

劉晏瑞 Ray Liu