Flutter Go Router no back button and nothing to pop

12.1k Views Asked by At

I am using Go Router on my flutter project and I noticed that the back button is not presented anymore. Even when I specifically add it I get the following error:

======== Exception caught by gesture =============================================================== The following GoError was thrown while handling a gesture: There is nothing to pop When the exception was thrown, this was the stack: #0 GoRouterDelegate.pop (package:go_router/src/delegate.dart:120:5) #1 GoRouter.pop (package:go_router/src/router.dart:284:21) #2 RecordDetailState.build. (package:random_me/screens/record/detail.dart:70:36) #3 _InkResponseState.handleTap (package:flutter/src/material/ink_well.dart:1072:21) #4 GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:253:24) #5 TapGestureRecognizer.handleTapUp (package:flutter/src/gestures/tap.dart:627:11) #6 BaseTapGestureRecognizer._checkUp (package:flutter/src/gestures/tap.dart:306:5) #7 BaseTapGestureRecognizer.handlePrimaryPointer (package:flutter/src/gestures/tap.dart:239:7)

  Widget build(BuildContext context) {
    AppTranslations.init(context);
    return Scaffold(
      appBar: AppBar(
          title: Text(TRANSLATION.record_detail),
          leading: IconButton(
            onPressed: () {
              GoRouter.of(context).pop();
            },
            icon: Icon(Icons.arrow_back_ios),
            //replace with our own icon data.
          )),

Edit: If I call

GoRouter.of(context).push(CategoryDetail.routeName); 

instead of

GoRouter.of(context).go(CategoryDetail.routeName);

it works;

2

There are 2 best solutions below

1
John On BEST ANSWER

Fixed: If I call

GoRouter.of(context).push(CategoryDetail.routeName); 

instead of

GoRouter.of(context).go(CategoryDetail.routeName);

it works;

1
Cyrille Dakhlia On

It depends on how you managed your GoRoutes in your GoRouter configuration.

Whenever you use navigation, you have a "Navigation Stack" to manage.

Look at the two configurations below:

Configuration 1 without sub-route

/// The route configuration.
final GoRouter _router = GoRouter(
  routes: <RouteBase>[
    GoRoute(
      path: '/',
      builder: (BuildContext context, GoRouterState state) {
        return const HomeScreen();
      },
    ),
    GoRoute(
      path: '/details',
      builder: (BuildContext context, GoRouterState state) {
        return const DetailsScreen();
      },
    ),
  ],
);

Configuration 2 with sub-route

/// The route configuration.
final GoRouter _router = GoRouter(
  routes: <RouteBase>[
    GoRoute(
      path: '/',
      builder: (BuildContext context, GoRouterState state) {
        return const HomeScreen();
      },
      routes: <RouteBase>[
        GoRoute(
          path: 'details', // Note that you don't prefix the route with '/' since it will get it from its parent route
          builder: (BuildContext context, GoRouterState state) {
            return const DetailsScreen();
          },
        ),
      ],
    ),
  ],
);

First of all, you always start at the / route, which means that your navigation stack will contain the screen/page associated to the route /, so here HomeScreen.

Now, in Configuration 1, if you use context.go('/details'), since the routes / and /details are at the same level, your Navigation stack will update to replace HomeScreen with DetailsScreen. Therefore, if you use context.pop() in DetailsScreen, you will have an error because in the Navigation stack, there is indeed nothing to pop.

In Configuration 2, if you also use context.go('/details'), since the route /details is a sub-route of /, your Navigation stack will add the screen/page associated to the route /details on top of the screens/pages it already has, which means that it will contain [HomeScreen, DetailsScreen]. In this case, if you use context.pop() in DetailsScreen, you will pop DetailsScreen and go back to HomeScreen.

This is the behaviour regarding the go method. Now if you use the push method, it always adds the new screen/page on the of the Navigation stack, which means that you will always be able to use context.pop without worrying (unless you are at the / route where you won't have anything to pop).

Now it can seem better to use push always rather than go that seems to present a limitation, but the answer is: it depends on your use case, what you want to achieve.

One big limitation of the push method is that it doesn't work well with Deep Linking, whereas go method works great with it, but requires you to manage well how your configure your routes.

I invite you to read this great article that explains with examples the differences between using go and push methods.