🤖

【Riverpod学習】Providerの種類〜FutureProviderについて〜

2024/10/13に公開

以下の公式を読みながらFutureProviderについて勉強したのでその備忘録です

https://riverpod.dev/docs/providers/future_provider

FutureProviderは、非同期処理を扱うためのRiverpodのプロバイダで、非同期コードの結果(Futureの結果)をアプリ内で管理するために使います。たとえば、ネットワークリクエストやデータベースからのデータ取得など、時間がかかる処理に適しています。これを使うことで、読み込み中やエラーの状態も簡単に扱えるため、非同期処理のUI表現がスムーズになります。

FutureProviderの概要

FutureProviderは、非同期処理(Future)を行い、その結果をUIで表示できるプロバイダです。通常のProviderは同期処理用ですが、FutureProviderは非同期処理の結果を待ってデータを提供します。

主な使用場面:

  • ネットワークリクエストや、ファイル読み込みなどの非同期処理。
  • エラー状態やローディング状態を簡単に管理する。
  • データのキャッシュを行い、複数のウィジェットで同じデータを使う際にも効率的に扱える。

例: JSONファイルの読み込み

次の例では、FutureProviderを使って、アプリ内のJSONファイルを読み込み、設定(Configurationオブジェクト)を取得する非同期処理を行っています。

1. 非同期関数の定義

まず、@riverpodアノテーションを使って、非同期処理を行う関数を定義します。この関数はFutureを返すため、FutureProviderがそれを監視します。


Future<Configuration> fetchConfiguration(FetchConfigurationRef ref) async {
  // assets/configurations.json からJSONファイルを読み込む
  final content = json.decode(
    await rootBundle.loadString('assets/configurations.json'),
  ) as Map<String, Object?>;

  // Configurationクラスのインスタンスを返す
  return Configuration.fromJson(content);
}

このコードでは、rootBundle.loadStringを使ってassets/configurations.jsonというファイルを読み込み、Configurationオブジェクトを作成しています。この操作は非同期的に行われ、完了するとFuture<Configuration>として返されます。

2. UIでの使用

次に、このFutureProviderの結果をUIで表示する方法を見ていきます。FutureProviderの結果はAsyncValueとして返されるため、エラー、読み込み中、データ取得完了の状態を簡単に管理できます。

Widget build(BuildContext context, WidgetRef ref) {
  // fetchConfigurationProviderの状態を監視
  final config = ref.watch(fetchConfigurationProvider);

  // 状態に応じて異なるUIを表示
  return switch (config) {
    // エラーが発生した場合
    AsyncError(:final error) => Text('Error: $error'),
    // データが取得できた場合
    AsyncData(:final value) => Text(value.host),
    // データがまだ読み込まれていない場合
    _ => const CircularProgressIndicator(),
  };
}

ポイント:

  • AsyncError: 非同期処理でエラーが発生した場合、そのエラー内容を表示。
  • AsyncData: 非同期処理が成功し、データが取得できた場合、そのデータを使ってUIを更新。
  • loading(_): 非同期処理がまだ完了していないときに、ローディングインジケーターを表示。
    このように、AsyncValueを使うことで、非同期処理の3つの状態(エラー、データ、読み込み中)を簡単に扱えます。

3. FutureProviderの使いどころ

  1. ネットワークリクエストや非同期ファイル読み込み
    たとえば、APIからデータを取得したり、外部のリソース(ファイルなど)を読み込む際に便利です。FutureProviderは、非同期処理の結果をキャッシュし、複数のウィジェットで同じ結果を使う場合でも、データが無駄に再取得されることがありません。

  2. 非同期データのエラーハンドリングとローディング状態の表示
    AsyncValueとして返されるため、非同期処理の結果が取得される前にローディングインジケーターを表示したり、エラーが発生したときにエラーメッセージを表示するのも簡単です。これは、ユーザーにとってスムーズなUI体験を提供するために非常に重要です。

4. FutureProviderとAsyncNotifierProviderの使い分け

FutureProvider

FutureProviderはユーザー操作による状態の変更はできません。たとえば、ネットワークから取得したデータを表示するだけなら適していますが、そのデータを元にさらにユーザー操作を反映させるのは難しいです。

使い方の例:

FutureProviderは、一度データを取得して、それを表示するだけのシンプルな非同期処理に向いています。

例: 設定ファイルやリモートAPIから一度データを読み込み、そのデータをアプリ内で表示する。データが変わることはない、もしくは頻繁には変わらない。

  • 非同期処理で結果を取得するだけ(リクエスト後に操作が不要)。
  • 状態を変更する必要がない(例えば、APIからデータを取得して一度だけ表示する場合)。

AsyncNotifierProvider

AsyncNotifierProviderは、FutureProviderのように非同期処理を扱うだけでなく、ユーザーの操作によって状態を変更できる 柔軟なプロバイダです。ユーザーがボタンを押したり、他のアクションを行った際に非同期処理を実行して、その結果に基づいて状態を更新します。

使い方の例:

AsyncNotifierProviderは、ユーザーのアクションに応じて非同期処理を開始し、その結果に応じて状態を更新する場面で使います。

例: タスク管理アプリで、リモートのサーバーからタスクリストを取得し、そのタスクに対して「完了」「未完了」を切り替える操作を行いたい場合。ユーザーがアクションを起こすたびに状態が変わるので、AsyncNotifierProviderの方が適しています。

  • 非同期処理の結果を取得しつつ、ユーザー操作による状態変更が必要な場合(タスクの状態変更、リモートサーバーとのデータ同期など)。
  • ユーザーの操作でデータの取得や更新を繰り返すような場合。

どちらを使うかは、非同期処理の結果を取得するだけでいいか(FutureProvider) 、それともユーザー操作に応じて状態を動的に変えたいか(AsyncNotifierProvider) で判断する

まとめ

  • FutureProviderは、非同期処理(ネットワークリクエストやファイル読み込みなど)を管理し、その結果をAsyncValueで返します。
  • 状態に応じたUIの表示(エラー、読み込み中、データ完了)が簡単に行えるため、非同期処理を扱う際に便利です。
  • キャッシュ機能があり、複数のウィジェットが同じデータにアクセスする際に効率的にデータを再利用できます。

Discussion