自主學習
翻譯
Angular
當你最愛的框架不像你想的那樣運作。
每個 Angular 開發者開發時都曾經碰過一些詭異甚至是荒謬的事情。本篇文章會探討一些這樣的案例並解釋為什麼框架的運作方式是如此。
FormControl.disable
觸發 valueChanges
使用 Reactive Forms 要禁用 FormControl
時,通常會使用 enable
和 disable
方法 :
我們把一個預設值是 "Default Value" 的FormControl
綁到 input 上,並監聽 valueChanges
的 Observable
。有一個切換"啟用/禁用"的按鈕。
這有什麼問題 ?
如果我們按下按鈕並且看控制台,會發現每次按下按鈕時都印出 "Default Value",即使值其實沒變。
如果表單很複雜並且會根據使用者設定或權限來啟用/禁用某些巢狀表單元件時,監聽 valueChanges
有時候會造成混淆。在 ngOnInit
中訂閱 valueChanges
,但是啟用/禁用依據的資料是透過 HTTP 呼叫取得,並且回應是在訂閱行為之後時,就會造成我們不希望的觸發。
雖然控制項本身的值並沒有改變,但是控制項如果是 FormGroup
或 FormArray
的一部分,當控制項被啟用/禁用時會改變父層 FormGroup
的值,FormGroup
的 valueChanges
是 子層控制項的 valueChanges
的組合,因此子層控制項必須發射 valueChanges
。
呼叫 enable
/disable
時帶上設定的參數 :
在作者另外一篇文章(在 Angular 中使用 Typescript Mixins)中提到,有時候繼承 base 元件是一件有用的事情。但有個情況是,Angular 的一個特別的功能並沒有像我們預期的那樣 :
下面的元件繼承了上面的 base 元件,而 base 元件有一個 Input
的屬性,當運行 app 時沒有問題,但是當使用 production 設定建置時會失敗,會說下面的元件沒有叫做 "something" 的 Input
屬性。
這是個 bug,參考GitHub issue
在子元件中特別宣告 inputs
:
告訴 Angular 編譯器,繼承的屬性是個 Input
。這是在 Angular 團隊修正問題前的暫時解法。
注意 : TSLint 會警告
inputs
這個屬性,可以用tslint:disable:use-output-property-decorator
註解來取消警告
ngOnChanges
vs ngOnInit
從字面上看,我們會覺得 ngOnInit
會是最先被觸發的生命週期方法,但有時候 ngOnChanges
會比 ngOnInit
早被呼叫。
ngOnInit
是在 view 開始渲染時呼叫,而 ngOnChanges
是在 Input
改變時呼叫,而 Input
改變不是必須等 ngOnInit
執行後才會發生。常常從父元件塞入的 Input
會在子元件開始渲染前就改變,因此 ngOnChanges
會在 ngOnChanges
前觸發。
如果 ngOnInit
中的程式邏輯會依據某些資料,而這些資料會在 ngOnChanges
中被處理時,就需要特別小心,特別是在監聽 FormControl.valueChanges
並且會根據元件的 Input
執行某些程式邏輯時。
在作者另外一篇文章(Angular Forms: Useful Tips)中提到,使用 Reactive Form 的一個問題是它並不保證是正確型別,而正確型別在使用 Typescript 的專案中是很必要的。非型別安全會導致不好的 IDE 體驗,型別無法被正確獲取,並導致一些重複的程式碼。
主要問題是 Reactive Form 是非常可客製化的,所以可能因此無法保持完整的型別安全。
可以參考上面提到的作者文章的建議。
NGRX 的每個 Action
都有由使用者提供的獨特識別。
上面的程式在做這件事 : loadData
這個Action發送時,呼叫 dataService
API 取得資料,取得成功後,發送 loadDataSuccess
的Action,把收到的資料放進 store 中。
打開 app 時看起來沒問題,但是打開開發者工具的 Network
標籤,會發現 API 被呼叫近乎無限次,甚至導致 Effect
卡在無窮迴圈。
造成無限呼叫的原因是,建立 loadData
和 loadDataSuccess
呼叫 createAction
時用了相同的字串。兩個不同的 Action 使用同樣的字串識別,當Action 被發送時會觸發 Effect
,然後又發送同樣的 Action。
用使用者提供的值作為 Action 的識別,比起做整個識別名稱系統來的容易,所以 NGRX 團隊用這種方式。但是馬上會改變,參見解決方式。
自己實作一個 ActionNames 的服務來避免產生 Action 時不小心使用到相同的識別名稱 :
上面是可以自己實作的解決方式。
NGRX 的最新版有他們團隊自己的解決方式實作,在 runtime 檢查識別的獨特性,當重複時會丟出錯誤。也可以使用這些TSLint規則 來檢查 Action 識別的獨特性
Angular 的功能相當廣大,有時候我們可能會誤以為自己完全了解他的運作方式,但總是會碰到驚喜。從錯誤中學習並了解其他開發者碰過的問題,能讓我們避免寫出 bug,也節省時間。