類似React/Vue的狀態管理
以下是管理狀態的最常見的方法:
* Widget 管理自己的狀態。
* Widget 管理子 Widget 狀態。
* 混合管理(父 Widget 和子 Widget 都管理狀態)。
一般的原則是:如果狀態是組件私有的,則應該由組件自己管理;如果狀態要跨組件共享,則該狀態應該由各個組件共同的父元素來管理。
下面是官方給出的一些原則可以幫助你做決定:
* 如果狀態是用戶數據,如復選框的選中狀態、滑塊的位置,則該狀態最好由父 Widget 管理。
* 如果狀態是有關界面外觀效果的,例如顏色、動畫,那么狀態最好由 Widget 本身來管理。
* 如果某一個狀態是不同 Widget 共享的則最好由它們共同的父 Widget 管理。
### 全局狀態管理
當應用中需要一些跨組件(包括跨路由)的狀態需要同步時,上面介紹的方法便很難勝任了。比如,我們有一個設置頁,里面可以設置應用的語言,我們為了讓設置實時生效,我們期望在語言狀態發生改變時,App中依賴應用語言的組件能夠重新 build 一下,但這些依賴應用語言的組件和設置頁并不在一起,所以這種情況用上面的方法很難管理。這時,正確的做法是通過一個全局狀態管理器來處理這種相距較遠的組件之間的通信。目前主要有兩種辦法:
1. 實現一個全局的事件總線,將語言狀態改變對應為一個事件,然后在APP中依賴應用語言的組件的initState 方法中訂閱語言改變的事件。當用戶在設置頁切換語言后,我們發布語言改變事件,而訂閱了此事件的組件就會收到通知,收到通知后調用setState(...)方法重新build一下自身即可。
2. 使用一些專門用于狀態管理的包,如 Provider、Redux,讀者可以在 pub 上查看其詳細信息。
## 跨組件狀態共享(Provider)
provider 原理圖

Model變化后會自動通知ChangeNotifierProvider(訂閱者),ChangeNotifierProvider內部會重新構建InheritedWidget,而依賴該InheritedWidget的子孫Widget就會更新。
我們可以發現使用Provider,將會帶來如下收益:
1. 我們的業務代碼更關注數據了,只要更新Model,則UI會自動更新,而不用在狀態改變后再去手動調用setState()來顯式更新頁面。
2. 數據改變的消息傳遞被屏蔽了,我們無需手動去處理狀態改變事件的發布和訂閱了,這一切都被封裝在Provider中了。這真的很棒,幫我們省掉了大量的工作!
3. 在大型復雜應用中,尤其是需要全局共享的狀態非常多時,使用Provider將會大大簡化我們的代碼邏輯,降低出錯的概率,提高開發效率。
Provider (opens new window)& Scoped Model(opens new window) 這兩個包都是基于InheritedWidget的,原理相似
Redux(opens new window) 是Web開發中React生態鏈中Redux包的Flutter實現
MobX(opens new window) 是Web開發中React生態鏈中MobX包的Flutter實現
BLoC(opens new window) 是BLoC模式的Flutter實現