maybeWhenとは?
Overview
maybeWhen
なるものを使う機会があったので調べてることにした。公式の解説だと...
一部のケースを意図的に処理せずに、 AsyncValueの状態を大文字と小文字を切り替えます。
AsyncValue が処理されないケースにあった場合は、 を返しますorElse。
デフォルトでは、Ref.refresh またはRef.invalidateによってトリガーされた場合、 whenは「読み込み」状態をスキップします (ただし、 Ref.watchによってトリガーされた場合は読み込み状態をスキップしません)。
AsyncValueが同時に複数の状態になる場合(プロバイダーをリロードするときや、有効なデータの後にエラーを発行するときなど)、 / /を呼び出すかどうかをカスタマイズするためのさまざまなフラグが提供される とき:loadingerrordata
skipLoadingOnReload(デフォルトでは false) Ref.watchloading が原因でプロバイダーが再構築された場合に を呼び出すかどうかをカスタマイズします。その状況では、when は 前の状態で/のいずれかを呼び出そうとします。errordata
skipLoadingOnRefresh(デフォルトで true) は、Ref.refresh またはRef.invalidate がloading 原因でプロバイダーが再構築される場合に を呼び出すかどうかを制御します。その状況では、when は 前の状態で/のいずれかを呼び出そうとします。errordata
skipError(デフォルトでは false) は、前の値dataが利用可能かどうかではなく、呼び出すかどうかを決定します。error
summary
どんなものなのか使ってみて考えてみたが、エラーの処理を分けるユースケースで使われているようだ。
こちらは参考にならなかった。Provider
の内容だった。
context.watch<CreateProfileState>() を呼び出すことで、状態が変化したときにウィジェットが確実に再構築されるようにします。 次に、Freezed によって生成された .maybeWhen() メソッドを使用して、必要な isLoading 変数と errorText 変数を抽出します。 この例では、noError、error、および読み込み状態を特定のウィジェットに直接マップできないため、これを行う必要があります。 代わりに、状態が UI に 1 対 1 でマップされている場合は、state.when(...) を使用して、状態ごとに異なるウィジェットを返すことができます。
私が書いてるコードだとこんな感じのがあります。
The body might complete normally, causing 'null' to be returned, but the return type, 'FutureOr<Weather>', is a potentially non-nullable type.
Try adding either a return or a throw statement at the end.dartbody_might_complete_normally
本文は正常に完了し、「null」が返される可能性がありますが、戻り値の型 'FutureOr<Weather>' は潜在的に null 非許容型です。
最後に return または throw ステートメントを追加してみてください。
AsyncNotifierを使うときに、return
かthrow
をつけろと怒られる!
この場合に、よくmaybeWhen
を使いますね。あってるか疑問ですが😅
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:weather_api/model/weather.dart';
import 'package:weather_api/repository/weather_repository.dart';
part 'weather_view_model.g.dart';
class WeatherViewModel extends _$WeatherViewModel {
FutureOr<Weather> build() {
return getWeatherData();
}
Future<Weather> getWeatherData() async {
state = const AsyncValue.loading();
state = await AsyncValue.guard(() async {
return await ref.read(weatherRepositoryImplProvider).getWeatherData();
});
return state.maybeWhen(
data: (data) => data,
orElse: () => throw Exception('API Error!'));
}
}
デバッグしながら、動作検証したらnull
のデータが入ってきたらエラー処理を実行してましたね。僕がプロバイダーの書き方を間違えてただけなんですけどね笑
// 自動保管で書いてしまった💣
Dio dio(DioRef ref) => Dio(ref));
正しい書き方はこっち⬇️
import 'package:dio/dio.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'dio_provider.g.dart';
Dio dio(DioRef ref) {
return Dio();
}
thoughts
自分のやってるオンラインサロンで大学生の子APIからデータが取ってこれなくて困ってるらしく教えてたんですけど、JSONがネストしてるのから、どうやってデータとれば良いのだろうと悩まされました😇
でも良い経験になりましたね。慣れれば、調べなくてもすぐにモデル作ったり、OpenAPIで使える。
もしerror log
を出したい時はどうする?
error
パラメーターを追加します。
return state.maybeWhen(
data: (data) => data,
error: (error, stackTrace) => throw Exception('例外を投げます $error'),
orElse: () => throw Exception('TaskState Error!'),
);
Discussion
これってProviderパッケージの使い方ではないでしょうか?
Riverpodの説明としては不適切な気がします!
こちらはAsyncNotifier使用時にreturnかthrowをつけろ警告されるわけでなく、関数の戻り値を非nullのWeather型を返すように指定しているので警告されるものかと思います。
taiseさんコメントありがとうございます!
ここは修正しました!
Freezedをnull許容しなくてもreturnかthrowは返さないといけなかったですね。
モデル: