catchError method

Future<void> catchError({
  1. required Future<void> actions(),
  2. bool isLoading = true,
  3. String keyLoading = LoadingKey.global,
  4. Future<void> onError(
    1. Object error,
    2. StackTrace stackTrace
    )?,
  5. Future<void> onFinally()?,
})

Executes a given asynchronous action within a try-catch block, handling loading states.

This method provides a convenient way to perform asynchronous operations while automatically managing loading states and error handling.

Parameters:

  • actions: A required function that contains the asynchronous operations to be performed.
  • isLoading: An optional boolean that determines whether to show/hide loading indicators. Defaults to true.

Usage:

await blocCatch(
  actions: () async {
    // Perform some asynchronous operations
    await fetchData();
    await processData();
  },
  isLoading: true, // Optional, defaults to true
);

The method will:

  1. Show a loading indicator if isLoading is true.
  2. Execute the provided actions.
  3. Hide the loading indicator after actions complete or if an error occurs.
  4. Log any errors that occur during execution.

Note: This method uses showLoading and hideLoading internally, which should be implemented in the concrete Bloc class or a mixin.

Implementation

Future<void> catchError({
  required Future<void> Function() actions,
  bool isLoading = true,
  String keyLoading = LoadingKey.global,
  Future<void> Function(Object error, StackTrace stackTrace)? onError,
  Future<void> Function()? onFinally,
}) async {
  try {
    if (isLoading) {
      showLoading(key: keyLoading);
    }
    await actions.call();
  } on Exception catch (e, stackTrace) {
    // Exceptions are expected, recoverable failures — route them to the
    // caller's handler or log them and carry on.
    if (onError != null) {
      await onError(e, stackTrace);
    } else {
      developer.log(
        'Error occurred: $e',
        name: 'Error',
        error: e,
        stackTrace: stackTrace,
      );
    }
  } on Error catch (e, stackTrace) {
    // An Error is a bug, not a recoverable condition. Log it, then let it
    // reach the zone handler and any crash reporter.
    //
    // A bare `catch` previously absorbed these too: a cubit closed during an
    // await would throw StateError from emit, get swallowed, and leave stale
    // UI with no crash report and no sign anything had gone wrong.
    //
    // The `finally` below still runs, so loading state is cleaned up before
    // the error propagates.
    developer.log(
      'Unrecoverable error: $e',
      name: 'Error',
      error: e,
      stackTrace: stackTrace,
    );
    rethrow;
  } finally {
    if (isLoading) {
      hideLoading(key: keyLoading);
    }
    if (onFinally != null) {
      await onFinally();
    }
  }
}