When writing your own StateNotifier
subclasses, it's quite common to use try/catch blocks to deal with Futures that can fail:
class SignOutButtonController extends StateNotifier<AsyncValue> {
SignOutButtonController({required this.authRepository})
: super(const AsyncValue.data(null));
final AuthRepository authRepository;
Future<void> signOut() async {
try {
state = const AsyncValue.loading();
await authRepository.signOut(); // this future can fail
state = const AsyncValue.data(null);
} catch (e) {
state = AsyncValue.error(e);
}
}
}
In such cases, AsyncValue.guard
is a convenient alternative that does all the heavy-lifting for us:
Future<void> signOut() async {
state = const AsyncValue.loading();
state = await AsyncValue.guard(() => authRepository.signOut());
}
sponsor

Build, Test and Distribute your Flutter Apps with Appcircle Mobile CI/CD. Enjoy hassle-free mobile CI/CD. Build your apps with speed using our M1 Architecture. Distribute Automatically to Apple App Store, Google Play Store, Huawei AppGallery. Create your own app store for Enterprise Distribution. Setup in a few minutes.
Here's how this method is implemented in the the AsyncValue
class:
abstract class AsyncValue<T> {
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);
}
}
}
Learn more here: AsyncValue.guard() method.
Happy coding!
Riverpod tip. 👇
— Andrea Bizzotto 💙 (@biz84) April 19, 2022
You can replace tedious try/catch blocks with AsyncValue.guard() inside your StateNotifier subclasses. pic.twitter.com/Q89nOrNrJD