guard<T> static method

Future<AsyncValue<T>> guard<T>(
  1. Future<T> future()
)

Transforms a Future that may fail into something that is safe to read.

This is useful to avoid having to do a tedious try/catch. Instead of:

class MyNotifier extends StateNotifier<AsyncValue<MyData> {
  MyNotifier(): super(const AsyncValue.loading()) {
    _fetchData();
  }

  Future<void> _fetchData() async {
    state = const AsyncValue.loading();
    try {
      final response = await dio.get('my_api/data');
      final data = MyData.fromJson(response);
      state = AsyncValue.data(data);
    } catch (err, stack) {
      state = AsyncValue.error(err, stack);
    }
  }
}

which is redundant as the application grows and we need more and more of this pattern – we can use guard to simplify it:

class MyNotifier extends StateNotifier<AsyncValue<MyData>> {
  MyNotifier(): super(const AsyncValue.loading()) {
    _fetchData();
  }

  Future<void> _fetchData() async {
    state = const AsyncValue.loading();
    // does the try/catch for us like previously
    state = await AsyncValue.guard(() async {
      final response = await dio.get('my_api/data');
      return Data.fromJson(response);
    });
  }
}

Implementation

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