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

Open-Source Backend Server for Flutter Developers. Appwrite is a secure, self-hosted solution that provides developers with a set of easy-to-use REST APIs to manage their core backend needs. You can build anything with Appwrite! Click here to learn more.
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