简体   繁体   中英

Flutter - Cubit & Navigation 2.0: emitting new page from page

I am trying to create a website with Flutter using Navigation 2.0 and BLoC pattern. To do so, I read the following guides:

However I am facing an issue where I am trying to push a new page from one of my website displayed page: the new page is never displayed!

To understand:

  1. Each pages are pushed via a MainNavigationCubit . This cubit's state (meaning pages) is maintained within the NavigationStack .
  2. My MainNavigationCubit is responsible for building the Navigator in my custom RouterDelegate (see code below). So upon a state change it rebuilds the Navigator with the proper list of pages.

The problem context:

  • I have a "Book" page which displays the details about a specific book.
  • In order to get the details, it expects a book id .
  • If the book id is invalid or not found, then the "404 not found page" is pushed via MainNavigationCubit .

This can happen, eg, if the user is manually inputting a correct URL to the book page but with an invalid ID.

However the "404 not found page" is never displayed although the MainNavigationCubit properly emits a new NavigationStack with relevant pages.


This is the code from my custom RouterDelegate :

@override
GlobalKey<NavigatorState> get navigatorKey => GlobalKey<NavigatorState>(debugLabel: 'main_navigation_key');

@override
Future<void> setNewRoutePath(PageConfig configuration) {
  if (configuration.route != homeRoute) {
    mainNavigationCubit.push(configuration.route, configuration.args);
  } else {
    mainNavigationCubit.clearToHome();
  }
  return SynchronousFuture(null);
}

@override
Widget build(BuildContext context) {
  return BlocBuilder<MainNavigationCubit, NavigationStack>(
    builder: (context, stack) {
      return Navigator(
        pages: stack.pages,
        key: navigatorKey,
        onPopPage: (route, result) => _onPopPage.call(route, result),
      );
    },
  );

@override
PageConfig get currentConfiguration => mainNavigationCubit.state.last;
bool _onPopPage(Route<dynamic> route, dynamic result) {
  final didPop = route.didPop(result);
  if (!didPop) {
    return false;
  }
  if (mainNavigationCubit.canPop()) {
    mainNavigationCubit.pop();
    return true;
  } else {
    return false;
  }
}

And this is the code from my "Book" StatelessWidget page:

@override
Widget build(BuildContext context) {
  if (bookId == -1) {
    context.read<MainNavigationCubit>().showNotFound(); // let's assume this will be properly handled when I'll be creating this page's BLoC.
  }
  return // full book details UI;
}

And just in case the code of MainNavigationCubit.showNotFound() :

void showNotFound() {
  clearAndPush(notFound);
}

void clearAndPush(String path, [Map<String, dynamic>? args]) {
  final PageConfig pageConfig = PageConfig(location: path, args: args);
  emit(state.clearAndPush(pageConfig));
}

OK, so after a lot of investigation I have found the reason for my issue.

As the documentation says: a Cubit won't notify listeners upon emitting a new state that is equal to the current state.

In my case, my MainNavigationCubit 's state is a NavigationStack which I took from this guide: https://medium.com/@JalalOkbi/flutter-navigator-2-0-with-bloc-the-ultimate-guide-6672b115adf

Looking at the code, the NavigationStack exposes methods that mutates an internal list of pages.

The problem is this list belongs to the current state , therefore modifying it means to also modify the current state.

As both current and new state rely on the same exact list, the Cubit won't emit the new state.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM