搜尋套件、儲存庫與 APP 分類

套件詳情v0.2.0

futuristic

讓在 StatelessWidget 內安全執行和重試 Future 成為可能。

AndroidiOSWebmacOSWindowsLinux
近 30 天下載
57
喜歡數
33
Pub 分數
160

安裝套件

flutter pub add futuristic

套件介紹

根據套件公開資料產生的選型評估,僅供參考。

Futuristic 是一個 Flutter/Dart 套件,可於 StatelessWidget 小部件中安全執行與重試 Futures。它透過提供一種乾淨、宣告式的 API,簡化無狀態環境中的非同步操作處理,無需狀態管理即可管理載入狀態、錯誤與重試。該套件與 Flutter 的小部件樹完全整合,並支援所有主要平台。當需要在維持響應式 UI 的同時取得資料或執行非同步任務時,非常適合使用。

適用情境

  • 在無狀態組件中獲取數據
  • 為失敗的非同步操作實現重試邏輯
  • 顯示載入和錯誤狀態
  • 使用非同步內容建構動態 UI
  • 簡化函數組件中的非同步處理

主要特色

  • 無狀態組件中的安全非同步執行
  • 內建重試機制
  • 支援載入與錯誤狀態
  • 最小化樣板程式碼
  • 跨平台相容性

適合對象

  • 大量使用 StatelessWidget 的開發者
  • 團隊避免使用複雜的狀態管理
  • 需要簡單非同步處理的專案
  • 頻繁資料獲取的UI
  • 針對多個平台的應用程式

使用建議

  • 不適合複雜的有狀態邏輯
  • 僅限基本重試策略
  • 需要理解 Futures 和 async/await
  • 可能無法取代完整的狀態管理解決方案
  • 最適合輕量級非同步操作

原始 README

以下為關聯原始碼儲存庫的 README 原文快照,最新內容請造訪原始碼儲存庫。

futuristic

Makes it possible to safely execute and retry a Future inside a StatelessWidget.

See the Mainstream package for a similar API for working with Streams.

Problem

If you've ever tried to use the FutureBuilder widget in Flutter, you've probably been surprised by its behavior. When used inside a StatelessWidget, it will re-execute its Future every time it is rebuilt. Since a widget can be rebuilt many times in Flutter (including due to hot reload), this can be undesirable if our Future calls a non-idempotent REST API endpoint, for example.

class Home extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return FutureBuilder(
      future: myExpensiveFuture(),  //Will be executed every time Home is rebuilt
      builder: (_context, snapshot) {
        ...
      },
    );
  }
}

To execute our Future only once, we could use a StatefulWidget, but now we have the extra boilerplate of using a StatefulWidget and holding onto our Future in a state variable.

class Home extends StatefulWidget {
  @override
  State<Home> createState() => _HomeState();
}

class _HomeState extends State<Home> {
  Future _future;

  @override
  void initState() {
    super.initState();
    _future = myExpensiveFuture();
  }

  @override
  Widget build(BuildContext context) {
    return FutureBuilder(
      future: _future,  // Will be executed only once
      builder: (_context, snapshot) {
        ...
      },
    );
  }
}

Solution

The problem with FutureBuilder is, ironically, that it takes a Future instance as its input. Instead, the Futuristic widget takes a Function that returns a Future and holds onto it in its own State. This means:

  • It can be used in a StatelessWidget.
  • It can let child widgets start or retry a Future.

Additionally, Futuristic provides:

  • Multiple builder callbacks to provide mutually exclusive initial/busy/data/error widget states.
  • Optional onData/onError callbacks to perform additional actions when a Future succeeds or fails.
  • Generic type safety for the data provided to callbacks. The type parameter <T> can be omitted if it can be inferred from the futureBuilder function.

Usage

We can use the Futuristic widget to wrap a single component like a button, or even an entire screen.

Button example

To start executing a Future in response to a button press, connect its onPressed handler to the start function provided in the initialBuilder callback.

Future<int> myFuture(int first, int second) async {
  await Future.delayed(const Duration(seconds: 1));
  return first + second;
}

class MyButton extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Futuristic<int>(
      futureBuilder: () => myFuture(1, 2),
      initialBuilder: (context, start) => RaisedButton(child: Text('Go'), onPressed: start),
      busyBuilder: (context) => CircularProgressIndicator(),
      errorBuilder: (context, error, retry) => RaisedButton(child: Text('Oops'), onPressed: retry),
      dataBuilder: (context, data) => Text(data.toString()),
    );
  }
}

The futureBuilder parameter is required.

The initialBuilder parameter is required if autoStart is false (see example below).

The optional busyBuilder displays a widget when the Future is busy executing. By default, it shows a centered CircularProgressIndicator. By displaying this, we inform the user that the operation is in progress and also prevent the Future from being triggered twice accidentally.

The optional errorBuilder displays a widget when the Future has failed, typically with an Error or Exception. This is provided as a parameter, together with a retry function that can be called to "retry" the Future.

The optional dataBuilder displays a widget when the Future has succeded. The resulting T value of the Future<T> is provided as a parameter to the callback. Note that this will be null in the case of a Future<void>.

Screen example

To automatically start executing a Future upon navigating to a screen, set the autoStart parameter to true instead of providing an initialBuilder. The busyBuilder will be displayed immediately.

Future<int> myFuture(int first, int second) async {
  await Future.delayed(const Duration(seconds: 1));
  throw Exception('something happened');
  return first + second;
}

class MyScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Futuristic<int>(
      autoStart: true,
      futureBuilder: () => myFuture(1, 2),
      busyBuilder: (context) => CircularProgressIndicator(),
      onError: (error, retry) => showDialog(...),
      onData: (data) => showDialog(...),
    );
  }
}

The futureBuilder parameter is required.

The optional onError callback can be used to handle the error event by displaying an alert dialog or sending to a logging provider, for example. It can be used in place of or together with the errorBuilder. A retry function is provided as a parameter that can be called to "retry" the Future. Be careful not to call retry without user interaction to avoid creating an infinite loop. This callback will not be retriggered as a result of a widget rebuild.

The optional onData callback can be used to handle a successful result by displaying an alert dialog or performing navigation. for example. This can be used in place of or together with the dataBuilder. This callback will not be retriggered as a result of a widget rebuild.

所屬分類

原始碼儲存庫

使用此套件的專案

暫無相關資料。