Flutter的不少靈感來自於React,它的設計思想是數據與視圖分離,由數據映射渲染視圖。因此在Flutter中,它的Widget是immutable的,而它的動態部分所有放到了狀態(State)中。因而狀態管理天然便成了咱們密切關注的對象。react
在以前咱們已經討論了關於在flutter中使用scoped_model進行狀態管理的應用。文章發出後,有許多同窗都在問我,到底redux和scoped到底誰更好。git
這個系列將會從這幾個狀態管理方案進行深刻研究:github
因此今天要和你們介紹的是在flutter中使用Redux進行狀態管理。 我但願各位在閱讀這篇文章以前,先仔細思考如下這幾個問題。編程
ok,咱們開始正式的介紹redux。redux
在咱們一開始構建應用的時候,也許很簡單。咱們有一些狀態,直接把他們映射成視圖就能夠了。這種簡單應用可能並不須要狀態管理。性能優化
可是隨着功能的增長,你的應用程序將會有幾十個甚至上百個狀態。這個時候你的應用應該會是這樣。markdown
這時候,咱們便迫切的須要一個架構來幫助咱們理清這些關係,狀態管理框架應運而生。架構
Redux是一種單向數據流架構,能夠輕鬆開發,維護和測試應用程序。app
這裏咱們以一個最簡單的CountApp舉例。簡單介紹flutter_redux/redux的用法。該項目完整代碼已上傳Github。框架
這是一個在不一樣頁面使用Redux共享狀態信息的app。這兩個頁面都依賴於一個數字,這個數字會隨着咱們按下按鈕的次數而增長。
咱們剛纔介紹了Redux的流程,狀態是由reducer生成並儲存在Store裏面的。Store更新狀態的時候,並不是更改原來的狀態對象,而是直接將reducer生成的新的狀態對象替換掉老的狀態對象。因此,咱們的狀態應該是immutable的。
import 'package:meta/meta.dart';
/** * State中全部屬性都應該是隻讀的 */
@immutable
class CountState{
int _count;
get count => _count;
CountState(this._count);
}
複製代碼
可能各位最開始接觸的時候對Action還會摸不着頭腦。action究竟是什麼?View如何發出action。其實,action只是咱們對狀態進行操做方法的一個代號而已。在咱們這個應用中,惟一的一個功能就是讓count的值+1,因此咱們這裏只有一個action。
/** * 定義操做該State的所有Action * 這裏只有增長count一個動做 */
enum Action{
increment
}
複製代碼
reducer是咱們的狀態生成器,它接收一個咱們原來的狀態,而後接收一個action,再匹配這個action生成一個新的狀態。
/** * reducer會根據傳進來的action生成新的CountState */
CountState reducer(CountState state,action){
//匹配Action
if(action == Action.increment){
return CountState(state.count+1);
}
return state;
}
複製代碼
Store接收一個reducer,以及初始化State,咱們想用Redux管理全局的狀態的話,須要將store儲存在應用的入口才行。而在應用打開時要先初始化一次應用的狀態。因此在State中添加一個初始化的函數。
//這段代碼寫在State中
CountState.initState(){ _count = 0;}
複製代碼
//應用頂層
void main() {
final store =
Store<CountState>(reducer, initialState: CountState.initState());
runApp(new MyApp(store));
}
複製代碼
flutter_redux提供了一個很棒的widget叫作StoreProvider,它的用法也很簡單,接收一個store,和child Widget。
class MyApp extends StatelessWidget {
final Store<CountState> store;
MyApp(this.store);
@override
Widget build(BuildContext context) {
return StoreProvider<CountState>(
store: store,
child: new MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: TopScreen(),
),
);
}
}
複製代碼
這裏建議你們把實際代碼對照下面的解釋一塊兒看。
StoreConnector<CountState,int>(
converter: (store) => store.state.count,
builder: (context, count) {
return Text(
count.toString(),
style: Theme.of(context).textTheme.display1,
);
},
),
複製代碼
要想獲取store咱們須要使用StoreConnector<S,ViewModel>。StoreConnector可以經過StoreProvider找到頂層的store。並且可以在state發生變化時rebuilt Widget。
咱們這個應用在第二個頁面中,經過點擊floatingActionButton發出了action,並通知reducer生成了新的狀態。
floatingActionButton: StoreConnector<CountState,VoidCallback>(
converter: (store) {
return () => store.dispatch(Action.increment);
},
builder: (context, callback) {
return FloatingActionButton(
onPressed: callback,
child: Icon(Icons.add),
);
},
),
複製代碼
以上即是在flutter中使用redux共享狀態信息的所有內容。
咱們的StoreConnector可以將store提取出信息並轉化成ViewModel,這裏實際上是有一個性能優化的點的。咱們這裏的例子很是簡單,它的ViewModel就只是一個int的值,當咱們ViewModel很複雜的時候,咱們可使用StoreConnector的distinct屬性進行性能優化。使用方法很簡單:須要咱們在ViewModel中重寫[==] and [hashCode] 方法,而後把distinct屬性設爲true。
Redux提供了一種簡單的方法來更新應用程序的狀態以響應同步操做。可是,它缺乏處理異步代碼的工具。咱們如何應對異步相應呢。
這裏就須要一個interrupt來處理異步請求,而後再發出新的action通知reducer生成新的State了。 這裏有brianegan大神寫的另一個幫助在flutter中使用redux處理異步請求的庫redux_thunk。我會在以後的文章中詳細介紹如何在redux中處理異步操做。
咱們發現,redux的確可以在flutter中很好的工做。在react中數據是沒有上行能力的,因此經過數據單向流動造成一個環來進行狀態管理。看上去彷佛並無把flutter中的優點徹底發揮出來。在這個簡單的例子中咱們也能夠看出,使用redux仍是稍微有些麻煩的,用的很差,可能會陷入redux地獄。學習成本偏高也是它的一大痛點。
固然,redux這套狀態管理架構已經比較成熟,假如您已經習慣redux,也可以快速經過flutter_redux輕鬆構建屬於您的狀態管理應用。
那麼你如今如何看待redux呢?
本次所用到的代碼已經上傳Github: github.com/Vadaski/Flu…
這篇文章參考瞭如下資料
你能在這些地方瞭解更多關於flutter-redux
若是您對flutter_redux還有任何見解或者文章的建議或者文章中有任何不對之處,歡迎在下方評論區以及個人郵箱1652219550a@gmail.com留言,我會在24小時內與您聯繫!
按理說下一章咱們將探索BLoC在Flutter中的實踐,而BLoC很是Reactive Programming,因此我決定先讓你們瞭解一些dart:Stream的知識再介紹它,因此下一篇文章咱們會介紹Stream以及流式編程,敬請關注。