fetchNextPage method

void fetchNextPage()
inherited

Fetches the next page.

If called while a page is fetching or no more pages are available, this method does nothing.

Implementation

void fetchNextPage() async {
  // We are already loading a new page.
  if (this.operation != null) return;

  final operation = this.operation = Object();

  value = value.copyWith(
    isLoading: true,
    error: null,
  );

  // we use a local copy of value,
  // so that we only send one notification now and at the end of the method.
  PagingState<PageKeyType, ItemType> state = value;

  try {
    // There are no more pages to load.
    if (!state.hasNextPage) return;

    final nextPageKey = _getNextPageKey(state);

    // We are at the end of the list.
    if (nextPageKey == null) {
      state = state.copyWith(hasNextPage: false);
      return;
    }

    final fetchResult = _fetchPage(nextPageKey);
    List<ItemType> newItems;

    // If the result is synchronous, we can directly assign it in the same tick.
    if (fetchResult is Future) {
      newItems = await fetchResult;
    } else {
      newItems = fetchResult;
    }

    // Update our state in case it was modified during the fetch operation.
    // This beaks atomicity, but is necessary to allow users to modify the state during a fetch.
    state = value;

    state = state.copyWith(
      pages: [...?state.pages, newItems],
      keys: [...?state.keys, nextPageKey],
    );
  } catch (error) {
    state = state.copyWith(error: error);

    if (error is! Exception) {
      // Errors which are not exceptions indicate that something
      // went unexpectedly wrong. These errors are rethrown
      // so they can be logged and investigated.
      rethrow;
    }
  } finally {
    if (operation == this.operation) {
      value = state.copyWith(isLoading: false);
      this.operation = null;
    }
  }
}