用 FutureBuilder 提升開發效率

常見場景

  1. 展現請求按鈕
  2. 用戶點擊按鈕,顯示loading
  3. 展現數據或者錯誤

抽象模式

  1. 展現請求按鈕(初始狀態
  2. 用戶點擊按鈕,顯示loading(請求中狀態
  3. 展現數據或者錯誤 (結束狀態(成功或失敗)

轉換成程序語言

以上三種現實狀況對應 AsyncSnapshot 三個狀態json

  • ConnectionState.none 初始態
  • ConnectionState.waiting 請求態
  • ConnectionState.done 完成態
    • snapshot.hasError 完成(異常)
    • snapshot.hasData 完成(正常)

使用 FutureBuilder 處理這個場景

這篇文章的主角,FutureBuilder 就是爲了解決這個問題存在的。它接收一個 Future 請求,和對應以上幾種狀況的 widget 回調。便可把數據和界面串聯起來,避免額外聲明僅用來傳遞數據用的變量網絡

提早聲明瞭一個 _showResult 變量,以表示頁面是否觸發請求。 而且封裝了一個 _fetch() 網絡請求。async

Future<Map> _fetch() async {
    return (await Dio().get("https://jsonplaceholder.typicode.com/users/1"))
    .data;
}
複製代碼

請求的結果是任意的,無論是封裝好的對象,maplist,均可以,只要是一個 Future<T>fetch

把這個 Future 調用安放到 FutureBuilderfuture 參數上, 並用 _showResult 來控制什麼時候來觸發這個請求。jsonp

FutureBuilder(
    future: _showResult ? _fetch() : null,
    ...
)
複製代碼

再把每個 Future 的結果對應的 widget 設置到 builder 參數上:ui

FutureBuilder(
    ...
    builder: (context, snapshot) {
      switch (snapshot.connectionState) {
        case ConnectionState.none: // -------- 初始態
          return RaisedButton(
            onPressed: () {
              setState(() {
                _showResult = true; // 點擊按鈕,觸發請求
              });
            },
            child: Text("start"),
          );
        case ConnectionState.waiting: // -------- 請求態
          return CircularProgressIndicator();
        case ConnectionState.done: // -------- 完成態
          if (snapshot.hasError) { // 異常
            return Text(
              '${snapshot.error}', 
              style: TextStyle(color: Colors.red),
            );
          } else { // 正常
            return Text(snapshot.data["name"]);
          }
          break;
        default:
          break;
      }
      return Container();
    },
  ),
複製代碼

總結

FutureBuilder 把數據請求的 Future<T> 中的數據 T 經過 BuilderConnectionState 衍生出全部可能性,並在每一個可能性裏 return 一個 Widgets。最終實現了 state -> UI 的目的spa

相關文章
相關標籤/搜索