Everything is widget,開發 Flutter 的時後,因為它是聲明式的語法,如果一個稍微複雜的頁面,很可能就會使用很多 widget ,進而容易寫出落落長的超大 widget(而且很複雜)。
這個情況在我現在維護的專案上尤其嚴重,在同一支檔案中有個三、四百行也是很常見的事(甚至更多)。
而當檔案行數越多時,越不容易看到整個頁面的架構,要找到要修改的點時,比起簡潔的檔案要困難的許多。
如果你也跟我一樣在維護複雜的 Flutter 專案,以下是我的建議:
按照 widget 的大小採用不同的命名方式
在檔案命名的時候,我習慣將整頁的 widget 的檔案名稱後面加上 _page
後綴字,如:login_page.dart
,當然其類別名稱就為 LoginPage
。 若是使用如 BottomNavigationBar
分隔不同的頁面,可以將檔案名稱後面加上 _layout
後綴字,表示是一個大的子頁面。 再者,假如是一個頁面中的小物件,可以加上 widget
或是不加。 當我們採用不同命名規則時,就可以輕鬆在檔案目錄內看到不同的檔案類型,如此就可以一眼看出我們該去哪個檔案修改。
將常常使用的小物件,包成共用的 widget
我們在修改的時候,有些時候經常會有類似的調整,如加上相同的 padding,使用相同的 BoxDecoration
... 等,如果在每個使用的地方都有特別的參數,當需要調整時,將會是一場災難,因為有可能會沒辦法一口氣修改所有的物件,造成不一致的情況。
有這種情況時,我們可以將這些細部的調整包成一個 widget 來使用,並將其放在獨立的檔案中,這樣一來,如果需要調整時,只要調整這個 widget,所有使用到的地方就可以一口氣作修改。
筆者目前在開發時,設計師採用的設計方式是原子設計 — 先設計物件,再將這些物件套用在畫面中,所以實作時,就可以先將這些物件建立好,之後就可以使用堆積木的方式來使用這些物件。
不過將這些設定值包起來時,需要考慮共用性,如果貿然的包起來,有可能會在後續的使用上更麻煩。如:將 Expanded
包起來,當使用的頁面上原本就有 Expanded 時,就有可能會發生錯誤。
使用 part
+ part of
拆分子物件
上一點提到如果有共用的子物件,我們可以把這個物件拆出並放在新檔案內,並在其他頁面重複使用。但如果我們不希望讓這個子物件可以被重複使用呢?換句話說,這個子物件只用於現在的頁面內,而我們只是為了方便閱讀,避免單一檔案太過冗長,於是將這個物件拆至其他的檔案中。 將物件由目前頁面拆出之後,放在新建的檔案內,我們可以在檔案的最上方加上 part of '主頁面檔案位置'
,表示這個檔案是這個檔案的一部分,並在原頁面上加入 part '子物件檔案位置'
用以宣告有一個子物件可以使用。 使用 part
、 part of
就可以讓目前頁面的內容更為簡便,也就更容易檢視。
使用狀態管理,如 BLoC
、Provider
...
一個頁面中,如果將頁面以及商業邏輯都包在一起,當新需求、 Bug 來臨,這種程式碼會讓我們難以修改。如果可以將邏輯的部分拆至 BLoC 或是 Provider 中,在該頁面只需要管理其狀態,也就是說狀態的調整邏輯就不會跟 UI 混在一起,當需要針對任何一部分修改都會相對容易,更不用說把商業邏輯與 UI 拆分,就更容易加上 Unit Test。
結論
因為 Flutter 的特性,容易造成在一個檔案包含太多內容、讓程式碼的長度太長而不易修改、除蟲。 為了避免這個情況,我們只要適當的將檔案內容搬移到其他地方,藉由一些簡單的重構方式,就可以大幅度縮減單一檔案的大小。
而將狀態管理邏輯整合進頁面內時,就可以讓 UI 與商業邏輯分離,UI 只會根據狀態來改變,而不需要處理其背後的邏輯。這樣一來,當需求來臨,我們就能夠輕易的找到修改的地方,快快樂樂的解決手上的問題。
後記
好久沒有寫 Flutter 文章了,前面的文章都是寫 Kotlin 為主,最近換到新公司,是以 Flutter 開發,而我又是唯一個 Flutter 工程師,我應該會有很多心得分享吧 XD
如果覺得我的文章不錯,有幫助到你,可以👏拍手鼓勵我。
謝謝