Chapter 09

[v0.14.0以下版] FutureProviderで非同期処理を購読する

村松龍之介
村松龍之介
2023.02.12に更新

FutureProvider - 単一の値を非同期的に作成する

FutureProvider = Provider + FutureBuilder とみなすことができます。

読み込み中 / エラー をハンドリングし、非同期処理が完了した時にWidgetを再構築させることが可能になります。

使用例としては、HTTPリクエストやファイルの読み取り、その他Futureを取り扱う処理全般で使用します。

Providerの宣言

以下は、プロジェクトの assets ディレクトリ配下に置いた config.json[1] ファイルを非同期で読み取り、
Map<String, Object?> 型に変換したものを提供するFutureProviderの例です。

final configProvider = FutureProvider<Map<String, Object?>>((ref) async {
  final jsonString = await rootBundle.loadString('assets/config.json');
  final content = json.decode(jsonString) as Map<String, Object?>;
  return content;
})

Widgetからの利用


Widget build(BuildContext context, ScopedReader watch) {
  // FutureProviderを読み取る(取得できる型は `AsyncValue<T>`)
  final config = watch(configProvider);

  return Scaffold(
    // AsyncValue は `.when` を使ってハンドリングする
    body: config.when(
      // 非同期処理中は `loading` で指定したWidgetが表示される
      loading: () => const CircularProgressIndicator(),
      // エラーが発生した場合に表示されるWidgetを指定
      error: (error, stack) => Text('Error: $error'),
      // 非同期処理が完了すると、取得した `config` が `data` で使用できる
      data: (config) {
        return Text(config['host']);
      }
    ),
  );
}

loading error 状態時のハンドリングが不要の場合は、 data?.value を使って簡略化することもできます。


Widget build(BuildContext context, ScopedReader watch) {
  // FutureProviderを読み取る(取得できる型は `AsyncValue<T>?`)
  final config = watch(configProvider).data?.value;
  return Scaffold(
    // Nullチェックは必要になるが、記述は簡略化できる
    body: Text(config?['host'] ?? 'loading...');
  );
}

参考リンク

FutureProvider | Riverpodドキュメントページ
https://pub.dev/documentation/riverpod/latest/riverpod/FutureProvider-class.html

config.json
{
  "appName": "SampleApp",
  "isDebug": true,
  "defaultAge": 20,
  "defaultGenders": ["male", "female"]
}
脚注
  1. JSONファイルの中身の一例↑ ↩︎

  2. https://api.dart.dev/stable/2.12.4/dart-core/Object-class.html ↩︎

  3. https://dart.dev/guides/language/type-system#type-inference ↩︎