admin管理员组

文章数量:1394056

I am using AsyncValue for async state as per docs but the error response from server is crashing the app. My riverpod is


final bookDetailsProvider = AutoDisposeAsyncNotifierProviderFamily<
    BookDetailsNotifier, AsyncValue<VirtualBook>, int>(
  () => BookDetailsNotifier(),
);

class BookDetailsNotifier
    extends AutoDisposeFamilyAsyncNotifier<AsyncValue<VirtualBook>, int> {
  @override
  Future<AsyncValue<VirtualBook>> build(int arg) async {
    return _loadBookDetails(arg);
  }

  Future<AsyncValue<VirtualBook>> _loadBookDetails(int id) async {
    try {
      final res = await ref.read(virualBooksRepositoryProvider).getBookById(id);
      return AsyncValue.data(res);
    } on ApiResponseError catch (e, s) {
      printRed('Error Response');
      printRed(e);
      return AsyncValue.error(e.message, s);
    } catch (e, s) {
      printRed(e);
      printRed(s);
      return AsyncValue.error('Something went wrong', s);
    }
  }
}

My UI is


class BookDetailsPage extends ConsumerWidget {
  const BookDetailsPage(this.bookId, {super.key});
  final int bookId;

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final bookDetails = ref.watch(bookDetailsProvider(bookId));

    return AppScaffold(
      titleIcon: Icons.book,
      title: 'Book Details',
      body: Padding(
        padding: const EdgeInsets.all(d_2),
        child: bookDetails.when(
          error: (error, stackTrace) {
            printYellow('Error');
            return Center(child: Text(error.toString()));
          },
          loading: () {
            printYellow('Loading');
            return const Center(child: CircularProgressIndicator());
          },
          data: (data) {
            printYellow('Got Data');
            printGreen('Data Type: ${data.runtimeType}');
            printGreen(' hasValue: ${data.hasValue}');
            printGreen(' hasError: ${data.hasError}');
            printGreen(' value: ${data.value}');
            final book = data.value;
            if (book == null) {
              return const Center(child: Text('Book not found'));
            }
            return ListView.separated(
              itemCount: book.chapters.length,
              separatorBuilder: (context, index) => const SizedBox(height: d_2),
              itemBuilder: (context, index) {
                final chapter = book.chapters[index];
                return ChapterTile(
                  index: index,
                  chapter: chapter,
                );
              },
            );
          },
        ),
      ),
    );
  }
}

Logs is

Clearly, I got 500 error from server, My state is AsyncError but the when method is calling the data callback instead of error callback. What may be the exact issue here?

I am using AsyncValue for async state as per docs but the error response from server is crashing the app. My riverpod is


final bookDetailsProvider = AutoDisposeAsyncNotifierProviderFamily<
    BookDetailsNotifier, AsyncValue<VirtualBook>, int>(
  () => BookDetailsNotifier(),
);

class BookDetailsNotifier
    extends AutoDisposeFamilyAsyncNotifier<AsyncValue<VirtualBook>, int> {
  @override
  Future<AsyncValue<VirtualBook>> build(int arg) async {
    return _loadBookDetails(arg);
  }

  Future<AsyncValue<VirtualBook>> _loadBookDetails(int id) async {
    try {
      final res = await ref.read(virualBooksRepositoryProvider).getBookById(id);
      return AsyncValue.data(res);
    } on ApiResponseError catch (e, s) {
      printRed('Error Response');
      printRed(e);
      return AsyncValue.error(e.message, s);
    } catch (e, s) {
      printRed(e);
      printRed(s);
      return AsyncValue.error('Something went wrong', s);
    }
  }
}

My UI is


class BookDetailsPage extends ConsumerWidget {
  const BookDetailsPage(this.bookId, {super.key});
  final int bookId;

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final bookDetails = ref.watch(bookDetailsProvider(bookId));

    return AppScaffold(
      titleIcon: Icons.book,
      title: 'Book Details',
      body: Padding(
        padding: const EdgeInsets.all(d_2),
        child: bookDetails.when(
          error: (error, stackTrace) {
            printYellow('Error');
            return Center(child: Text(error.toString()));
          },
          loading: () {
            printYellow('Loading');
            return const Center(child: CircularProgressIndicator());
          },
          data: (data) {
            printYellow('Got Data');
            printGreen('Data Type: ${data.runtimeType}');
            printGreen(' hasValue: ${data.hasValue}');
            printGreen(' hasError: ${data.hasError}');
            printGreen(' value: ${data.value}');
            final book = data.value;
            if (book == null) {
              return const Center(child: Text('Book not found'));
            }
            return ListView.separated(
              itemCount: book.chapters.length,
              separatorBuilder: (context, index) => const SizedBox(height: d_2),
              itemBuilder: (context, index) {
                final chapter = book.chapters[index];
                return ChapterTile(
                  index: index,
                  chapter: chapter,
                );
              },
            );
          },
        ),
      ),
    );
  }
}

Logs is

Clearly, I got 500 error from server, My state is AsyncError but the when method is calling the data callback instead of error callback. What may be the exact issue here?

Share Improve this question asked Mar 11 at 19:02 Kedar KarkiKedar Karki 5487 silver badges17 bronze badges 1
  • By default, riverpod wraps Futures and Streams with AsyncValue. There is no need to do that manually. When you are reading bookDetails, are you getting an object of type AsyncValue<AsyncValue<VirtualBook>>? In that case, data is of type AsyncError<VirtualBook> and that is not handled as an error. – Dan R Commented Mar 11 at 19:25
Add a comment  | 

1 Answer 1

Reset to default 1

My bad, The AsyncNotifier automatically wraps the state into AsyncValue. So in my code, its a AsyncValue inside a AsyncValue which gave this behaviour. Converting state of AsyncValue<VirtualBook> to just VirtualBook solved the issue.

本文标签: flutterRiverpod AsyncValuewhen is not triggering the error builderStack Overflow