[Riverpod] FutureProviderやAsyncNotifierProviderでExceptionした時にログを表示する
Riverpodで開発をしていると FutureProvider
や AsyncNotifierProvider
は日常的に使うかと思います。
それぞれが初期化中にエラーを発生させるとAsyncError
となり、ref.watch(provider).when(data: ...)
でエラー時のUIを構築できます。
しかし、エラーログがコンソールに表示されないので、開発中に困ることが多々ありました。
そのため、アプリ全体でFutureProviderや
AsyncNotifierProvider`の初期化中のエラーをログとして表示するようにしました。
riverpodが2.4.6以上
後述しますが、バージョンが2.4.5以下の場合、この方法では上手く行きません。
2.4.6以上の場合に使える方法です。
① ProviderObserverのproviderDidFailをoverrideしたクラスを作る
class _AppObserver extends ProviderObserver {
void providerDidFail(
ProviderBase<Object?> provider,
Object error,
StackTrace stackTrace,
ProviderContainer container,
) {
// ここでログを表示する。
final logger = Logger();
logger.e(
error,
error: error,
stackTrace: stackTrace,
);
}
}
② ProviderScopeのobserversに指定する
main.dart
とかで ProviderScope
を使っていると思いますが、ovservers
に_AppObserver
を追加します。
runApp(
ProviderScope(
observers: [_AppObserver()], // ここに追加
child: AppMaterialApp(
home: const TextFieldScreen(),
),
),
);
riverpodが2.4.5以下
個人で開発しているプロダクトのバージョンが最初2.4.4だったため、上記の方法で上手く行きませんでした。
原因としては、providerDidFail
がトリガーされないためログが表示されていなかったのですが、
公式のPull requestsを見ると、こちらで改善されているみたいで2.4.6のバージョンに含まれているみたいです。
もちろんバージョンを上げれば解決するので、それでもいいですがバージョンを上げずにログを表示する方法も書いておきます。
① didUpdateProvideを使う
2.4.5以下だとproviderDidFail
がトリガーされないため、代わりにdidUpdateProvider
を使います。
ただ、そのまま使ってしまうとProvider更新時全てでログが流れてしまうため newValue is AsyncError
の場合だけログを表示します。
class _AppObserver extends ProviderObserver {
void didUpdateProvider(
ProviderBase<Object?> provider,
Object? previousValue,
Object? newValue,
ProviderContainer container,
) {
if (newValue is AsyncError) {
final logger = Logger();
logger.e(
newValue.error.toString(),
error: newValue.error,
stackTrace: newValue.stackTrace,
);
}
}
}
② ProviderScopeのobserversに指定する
あとはは2.4.6以上と同じでobserversに指定してあげます。
runApp(
ProviderScope(
observers: [_AppObserver()], // ここに追加
child: AppMaterialApp(
home: const TextFieldScreen(),
),
),
);
参考
Discussion