🧖

【Flutter】RiverpodのAsyncValueのguardメソッドが便利

2022/07/09に公開2

ととのっていきましょう。AsyncValueについてのリファクタリングの小ネタです。

AsyncValueとは

RiverpodのAsyncValue(公式ドキュメント)というクラス。
これを使うことで、非同期でデータを処理する際、ローディング中か、エラーが発生したかといった状態を簡単に管理できます。
ローディングとエラーのハンドリング漏れや、人によるコーディングのバラツキを減らせるでしょう。

便利なguardメソッド

AsyncValueの公式ドキュメントを改めて見ていたら、guardメソッドなるものをみつけました。
ゴニョゴニョと説明するよりサンプルコードを見ていただくとその便利さが伝わるでしょう。

↓のようなStateNotifierクラスがあり、_fetchDataメソッドで非同期でSampleDataを取得するとします。

class SampleScreenModel extends StateNotifier<AsyncValue<SampleData>> {
  SampleScreenModel(this._reader) : super(const AsyncValue.loading()) {
    _fetchData();
  }

  final Reader _reader;
  SampleService get _sampleService => _reader(sampleServiceProvider);

  Future<void> _fetchData() async {
    // ローディングを開始
    state = const AsyncValue.loading();

    // エラーハンドリングしてデータを取得
    try {
      final data = await _sampleService.fetchData();
      state = AsyncValue.data(data);
    } catch (err, stack) {
      state = AsyncValue.error(err, stackTrace: stack);
    }
  }
}

このtry/catchの部分に注目してください。
AsyncValueのguardメソッドを使うと、↓のようになります。

    try {
      final data = await _sampleService.fetchData();
      state = AsyncValue.data(data);
    } catch (err, stack) {
      state = AsyncValue.error(err, stackTrace: stack);
    }

これが、

    state = await AsyncValue.guard(() async {
      final data = await _sampleService.fetchData();
      return data;
    });

これになります。
冗長だったエラーハンドリングがguardメソッドによってシンプルになりましたね。

guardメソッドの定義

定義は↓のようになっています。

  static Future<AsyncValue<T>> guard<T>(Future<T> Function() future) async {
    try {
      return AsyncValue.data(await future());
    } catch (err, stack) {
      return AsyncValue.error(err, stackTrace: stack);
    }
  }

try/catchをラップしていて、エラーも返してくれていることがわかります。

Discussion

tigeeertigeeer

めっちゃ便利ですね!知りませんでした
しかも今回のサンプルコードだと↓まで省略できちゃいますね!!

state = await AsyncValue.guard(_sampleService.fetchData);