[譯]讓我來幫你理解和選擇Flutter狀態管理方案

This article is from Medium written by Jorge Coca, Thank you Jorge for allowing me translate your awesome article into Chinesereact

本文來源於Medium,由Jorge Coca撰寫,並准許我翻譯成中文git

狀態管理在Flutter中是一個很熱的話題。可選的方案有不少,這可能很好,但卻很容易陷入其中,在項目中選擇最適合方案時感到迷失。我也是,不過我已經找到了適合個人方案,讓我來分享給你。github

分享時刻

爲了找到適合需求的方案,頭一件事就是確認需求,而後設置目標和指望。對我而言,我定義了以下:redux

  • 容許穩定的開發速度,而不犧牲代碼質量
  • 分離展現邏輯和業務邏輯
  • 容易理解;難以破壞
  • 可預期而且能夠普遍部署

在給定了這些限制後,咱們來看看咱們可選的方案:設計模式

  • 使用StatefulWidgets的setState()
  • ScopedModel
  • BLoC(Business Logic Component)
  • Redux

理解局部狀態和全局狀態的不一樣

在深刻分析不一樣方案前,有一件事可能會幫助咱們更好的理解怎樣選擇——什麼是局部狀態,什麼是全局狀態安全

爲了這件事,咱們來考慮一件事:想象一個簡單的登錄表單,用戶能夠輸入用戶名和密碼,若是登錄成功,就能夠從後臺得到到id。在這個例子中,登陸表單的任何驗證類型,均可以考慮爲局部狀態,由於這些規則僅適用於這個組件,而App的其餘部分不須要知道這個類型。可是從後臺獲取的id,就須要考慮成全局狀態,由於它影響整個app的做用域(未登陸和已登錄),並且可能別的組件會依賴它。bash

簡而言之:告訴我結果

若是你不想等過久,或者對深刻探索不感興趣,下面這個表能夠快速告訴你個人發現:架構

個人建議是:使用BLoC進行局部狀態管理,使用Redux進行全局狀態管理。特別是對持續迭代的複雜應用而言。app

爲何不用setState()?

快速製做原型的時候,在widget中使用setState()很是爽,並且你會當即獲得反饋。可是這並不能幫助咱們實現目標:展現邏輯和業務邏輯在同一個類裏,打破了乾淨和高質量代碼的原則。之後應用的規模擴張的時候,代碼的維護將會是一個挑戰。所以除了快速原型設計,我不建議使用setState()。less

ScopedModel,正確方向上的一步

ScopedModel是Brian Egan維護的第三方包。它讓咱們建立Model對象,而後在咱們須要的時候調用notifyListeners();例如,在咱們的模型(model)屬性改變的時候:

class CounterModel extends Model {
  int _counter = 0;
  int get counter = _counter;
  void increment() {
    _counter++;
    notifyListeners();
  }
}
複製代碼

在咱們的widget中,咱們可使用ScopedModelDescendant來響應模型的變化:

class CounterApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) { 
    return new ScopedModel<CounterModel>(
      model: new CounterModel(),
      child: new Column(children: [
        new ScopedModelDescendant<CounterModel>(
          builder: (context, child, model) => new Text('${model.counter}'),
        ),
        new Text("Another widget that doesn't depend on the CounterModel")
      ])
    );
  }
}
複製代碼

和setState()相反,若是咱們使用ScopedModel,就能夠分離展現邏輯和業務邏輯,這樣就很好了。可是也會有一些侷限:

  • 若是你的模型變得複雜,挑選調用notifyListeners()的時機以防止不必的更新,將會是一個挑戰。
  • Model的API並無準確描述UI應用程序的異步性。

綜上,除非狀態很容易控制,不然我不建議你使用ScopedModel;若是你的應用足夠複雜,我不相信這是支持複雜性和迭代的正確答案。

BLoC,一個強大的方案

BLoC是一個被Google創造並使用的設計模式;他會幫助咱們完成這幾件事:

  • 分離展現邏輯和業務邏輯
  • 擁抱UI應用的異步性
  • 能夠在不一樣的dart應用中複用,不管是Flutter應用仍是Angular dart應用

BLoC背後的想法很簡單:

  • BLoC開放Sink<I>API來描述咱們組件的異步輸入
  • BLoC開放Stream<T>API來描述咱們組件的異步輸出
  • 最終,咱們使用StreamBuilderwidget來管理數據流,咱們不須要再維護對數據流的訂閱和widget的重繪

由於它被Google重度使用和推薦,他們有個很是好的例子:github.com/filiph/stat…


我很是推薦你在應用中使用BLoC,特別是管理局部狀態。

即便是全局狀態管理,我相信它也會有很好的解決;可是你將會在這個領域面臨一些挑戰,例如怎麼在不一樣UI組件中插入BLoC更合適,我想這是Redux的閃光點。

Redux和BLoC,對我來講完美的搭配

在文章的開頭,其中一個目標就是找到一個能夠普遍應用而且可預期的方案。好吧,就是Redux。

Redux是一個設計模式,融合了一些工具,來幫助咱們管理全局狀態。它創建在3個基本原則上:

  • 單一事實來源:你的整個應用的狀態,都存在在單一的store中,而且以一個樹狀對象存在
  • 狀態是隻讀的:改變狀態的惟一方法就是發射action,一個描述發生了什麼的對象
  • 改變被純函數處理:爲了說明action怎麼改變狀態,你想要寫一個純函數的reducer(譯者注:純函數就是這個函數內部不存儲狀態,在相同的參數的前提下,不管在什麼時候調用,返回值嚴格一致)

Redux是網頁開發着普遍使用的設計模式(譯者注:好比用在React.js中),因此在移動端也有普遍的基礎,會讓咱們互相收益。

Brian Egan維護redux和flutter_redux,並且創造了一個很是棒的ToDo 應用, 集成了不少不一樣的架構模式,包括Redux。

鑑於Redux的全部特性,我徹底建議使用它來管理全局狀態,可是若是你想擴張你的應用,請確保在Redux架構裏面不包含局部狀態。

最後的思考

這裏並無正確與錯誤答案。爲了選一個工具,或者應用一個設計模式,理解你本身的需求很是重要。對我和個人需求來講,Redux和BLoC搭配能幫助我快速安全地擴張個人應用。同時由於工具的可用性被社區很好地理解,更多的開發者開始使用它。話說回來,每一個人都有不一樣的需求和看問題的角度,重要的是始終有好奇心,去學習和思考,什麼纔是最好的方案

你能夠訪問原做者的GitHub

也歡迎關注個人更多文章,以及個人GitHub

相關文章
相關標籤/搜索