csells / go_router

The purpose of the go_router for Flutter is to use declarative routes to reduce complexity, regardless of the platform you're targeting (mobile, web, desktop), handling deep linking from Android, iOS and the web while still allowing an easy-to-use developer experience.
https://gorouter.dev
442 stars 96 forks source link

Is there any way to do nested routing with stack inside nested routes? #58

Closed Moussenger closed 2 years ago

Moussenger commented 2 years ago

Probably the title is a bit tricky. Let me write down here an example to expose what I am talking about:

You have an app with a kind of nested navigation. Let's say a bottom navigation bar that remains as is in the nested routes. This route is in the root (/). Now, you have three buttons in the navigation bar, let's say user, friends and settings (as routes /user, /friends, /settings). These routes are going to be nested, handled by the navigation bar screen and open different widgets inside.

/friends opens the nested screen with the list of friends of the current user. In this page, you are able to go deeper selecting a friend from the list to see the profile. That would be the route /friends/:friend_id. This details routing has to happen in the same nested view of the navigation bar, but currently, this is happening as top-level navigation.

The router is defined kind of:

final _router = GoRouter(
    initialLocation: "/user",
    routes: [
      GoRoute(
        path: '/:kind(user|friends|settings)',
        pageBuilder: (context, state) {
          final tab = state.params['kind']!;

          return MaterialPage<void>(
            key: state.pageKey,
            child: NavBarPage(tab: tab),
          );
        },
        routes: [
          GoRoute(
            path: ':friend_id',
            pageBuilder: (context, state) {
              final friendId = state.params['friend_id']!.toString();

              return MaterialPage<void>(
                key: state.pageKey,
                child: FriendDetails(friendId: int.parse(friendId)),
              );
            },
          ),
        ],
      )
    ],
    errorPageBuilder: (context, state) => MaterialPage<void>(
      key: state.pageKey,
      child: Center(child: Text(state.error.toString())),
    ),
  );

Is there some stuff you can do to open the details friend screen nested to the navigation bar too without handle all this ceremony by your own out of the router?

Is there any stuff you can do to handle the back button inside this nesting scenario to come back from friend details to friends list without get out of the app?

Just as a bonus question: Is there any way to handle recursive deep routes? Example: Friends > detail of a friend with its list of Friends > other friend > detail of the other friend with its list of the other friends... The route would be something like: /friends/1/friends/3/friends... I was thinking in using a kind of redirection param as `/friends/3?friends_of=[/friends/2], but this doesn't keep the back scenario, right?

TimWhiting commented 2 years ago

I was looking for a similar feature:

For example nested navigation as in auto_route where you specify a AutoRouter as a nested router outlet / router view, so that the whole page doesn't rebuild when a parameter changes. Makes it clearer where the navigation is happening. There are similar router views in many web frameworks. https://pub.dev/packages/auto_route#nested-navigation

Very useful for dashboard or app style web pages.

csells commented 2 years ago

Have you checked out the nested navigation sample that comes with go_router? Is it inadequate in some way?

Moussenger commented 2 years ago

Yes. I've checked it. That's one of the reasons why I wrote my question, indeed. The library works really well, but the use case being exposed here is a little different from the example.

In the example, when you are going to see a person from a family list, you get a totally new screen hidden in the tab bar. What I need or I am trying to get is that the navigation to a particular person happens inside the tab, without hiding the whole screen with the new screen. Just an inner stack inside the tab.

I hope this is clear, otherwise, I could try to explain it with images.

csells commented 2 years ago

Thanks, @Moussenger. I do think I'm going to need some pics. Sorry.

Moussenger commented 2 years ago

That's ok, it's a little tricky to explain graphical things just with words. Let's go (this example is using the router in the main post of the issue):

I have this screen (/friends):

image

When I go to friend 1, I get this page (/friends/1):

image

I get this screen with an AppBar showing the back button and working as expected. But what I am trying to get is this screen when I go to /friends/1:

image

So, you still have the navigation bar at the bottom and the back button just going back to the friend's list, handling the back stack as normal.

csells commented 2 years ago

You are in luck. I'm developing something very like that for my own app (for which I built go_router in the first place). I'll pull together a sample and share it.