setResultAsync method

Future<Result<T>> setResultAsync(
  1. FutureOr<Result<T>> fetchResult()
)

Sets the value (result) of this notifier asynchronously using the result returned by the provided function.

Before executing the provided function, the current state will be set to Loading. The result will then be set to the return value of the function call, if successful, or Error if an error occurs (i.e. if the function throws an exception). If this notifier was cancelled during the asynchronous gap, the result of fetch will be ignored and an Error will be returned by this method (i.e. Error.cancelled).

Note that the Future returned by this method will always complete with a value, never an error. If an error occurs, it will be represented as an Error result.

The return value of this method is the current value (result) after executing the provided function. Instead of using this, consider using future instead, which will await the next successful data or error result of this notifier.

Implementation

Future<Result<T>> setResultAsync(FutureOr<Result<T>> Function() fetchResult) async {
  assert(ChangeNotifier.debugAssertNotDisposed(this));
  toLoading(); // Important to always create a new Loading value, to indicate a new loading operation has started

  final previousResult = value;
  Result<T>? abortIfDisposedOrCancelled() {
    if (!_active) {
      return Error.disposed();
    } else if (previousResult != value) {
      // Result changed during asynchronous gap, likely due to cancellation - abort
      // TODO: Log warning about concurrent modification unless cancelled
      return Error.cancelled();
    }
    return null;
  }

  try {
    final fetchedResult = await fetchResult();

    final shouldAbortResult = abortIfDisposedOrCancelled();
    if (shouldAbortResult != null) return shouldAbortResult;

    value = fetchedResult;
  } catch (error, stackTrace) {
    final shouldAbortResult = abortIfDisposedOrCancelled();
    if (shouldAbortResult != null) {
      return shouldAbortResult;
    } else {
      // CancelledException and NoDataException should end up here (i.e. update the result to Error)
      toError(error: error, stackTrace: stackTrace);
    }
  }
  return result;
}