iT邦幫忙

2022 iThome 鐵人賽

DAY 7
1
Mobile Development

關於 Flutter 開發的一些設計雜談系列 第 7

Day 7 - 跨元件分享狀態,橫跨數代的共同秘密

  • 分享至 

  • xImage
  •  

在前幾天的 Game List 的例子中,我們消除了 onTap 層層傳遞的問題。但是,如果我們仔細觀察的話,會發現 Game 也是同樣的情況,只要底層的哪個 Widget 需要 Game,中間層的 Widget 就需要當中間人,代為傳遞參數。

it_img_7_1.png
https://dartpad.dev/?id=831bf7d1714ef8d70daa0e473d5e2bed

中間的 Widget 傳遞這個參數,自己卻是用不到,這個問題在上一張討論如何傳遞 callback 時也有討論到。今天就來聊聊如何簡化設計。

InheritedWidget

Flutter 有提供許多基礎類型的 Widget,例如:StatelessWidget, StatefulWidget,而其中有一類 Widget 稱作 InheritedWidget。透過 InheritedWidget,我們能有效地讓子層可以跨過父層,直接存取 InheritedWidget。使用這個特性,我們就能避免層層傳遞 Game 的問題了。

it_img_7_2.png
it_img_7_3.png
https://dartpad.dev/?id=90fdfc781c4d43360eeb178174918381

經過修改之後,在上面的程式碼中,我們在頂層使用 GameInfo 這個 InheritedWidget,讓 GameInfoSection 和 GameActionSection 自己去取得 GameInfo,最後 GameItemView 也不需要幫忙傳遞 Game 了。

Provider

當我們每次想要 Widget Tree 中,縱向的分享資料時,我們都得寫一個 Widget 並讓他繼承 InheritedWidget,但是其實在 Flutter 眾多套件中,有一個能幫助我更簡單的使用 InheritedWidget,那就是 Provider

it_img_7_4.png
it_img_7_5.png
https://dartpad.dev/?id=1ec4a9a9cb445e7b50bfb6974628d62d

可以發現使用 Provider 之後的程式碼,簡潔非常多,不需要使用繼承,也不需要特別定義一個新的 Widget,直接使用 Provider 並放入 game 就好。由於 Provider 裏頭其實就是 InheritedWidget,透過 Provider 我們能用組合的方式去使用 InheritedWidget,而不是繼承,想比喻繼承,我們傾向於使用組合,也是一個有名的規則:以組合取代繼承

值得一提的是,InheritedWidget 是狀態管理的基礎,所以也使得作為 InheritedWidget 的 Wrapper,Provider 也被大量套件引用,其中最知名的就是 Bloc 了。

用 Provider 傳遞按鈕事件

回想前兩天的主題,按鈕傳遞我們也能把 callback 放在 Provider,當子 Widget 渲染時,從 Provider 身上讀取 callback。但其實這個作法並不太合適,因為當我們從 Provider 讀取 callback 時,也意味著使用這個按鈕必須提供相應的 Provider,即使用他的人不需要按鈕有行為。大多時候,使用 Provider 傳遞狀態會比較合理,因為畫面顯示與資料是一致的,不同的資料會有不同的畫面。相比於資料,按鈕行為就很可能會因為畫面不同,而有不同的功能,所以使用 Provider 來傳遞按鈕事件,就會降低按鈕元件通用性。

結論

InheritedWidget 讓我們可以往子層 Widget 共享資料,避免過多的傳遞參數,畢竟沒有參數的方法或物件最好用。雖然 InheritedWidget 好用,但是在實戰中,我們還是傾向於使用 Provider,畢竟組合還是比繼承要來得有彈性。


上一篇
Day 6 - 用 NotificationListener 處理按鈕事件
下一篇
Day 8 - 當狀態遇上複雜的操作邏輯
系列文
關於 Flutter 開發的一些設計雜談30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言