GoRouter嵌套路由重复问题:统一电影详情路由并保留根菜单?
解决StatefulShellRoute下电影应用导航的三个问题
针对你遇到的路径不统一、路由重复、递归跳转问题,我们可以通过将共享路由挂载到StatefulShellRoute的全局子路由中,配合导航器key控制跳转上下文来解决,具体方案如下:
核心思路
- 把电影详情这类全局共享路由抽离成独立配置,挂载在
StatefulShellRoute的routes参数下(而非每个分支内部),确保路径统一且无需重复定义; - 使用导航器key区分根导航(控制底部菜单)和分支导航,避免跳转时出现递归嵌套;
完整代码示例
首先抽离共享的电影详情路由:
// 全局共享的电影详情路由,只需定义一次 final GoRoute movieDetailRoute = GoRoute( path: '/movies/:id', builder: (context, state) { final movieId = state.pathParameters['id']!; return MovieDetailScreen(movieId: movieId); }, // 后续扩展子路由(如评论页)只需在这里添加 routes: [ GoRoute( path: 'reviews', builder: (context, state) => MovieReviewsScreen(movieId: state.pathParameters['id']!), ), ], );
然后配置GoRouter:
// 导航器key,区分根导航和各分支导航 final _rootNavigatorKey = GlobalKey<NavigatorState>(); final _homeNavigatorKey = GlobalKey<NavigatorState>(); final _searchNavigatorKey = GlobalKey<NavigatorState>(); final router = GoRouter( navigatorKey: _rootNavigatorKey, routes: [ StatefulShellRoute.indexedStack( navigatorKey: _rootNavigatorKey, // 根导航器,负责底部菜单的展示 branches: [ StatefulShellBranch( navigatorKey: _homeNavigatorKey, routes: [ GoRoute( path: '/', builder: (context, state) => const HomeScreen(), ), ], ), StatefulShellBranch( navigatorKey: _searchNavigatorKey, routes: [ GoRoute( path: '/search', builder: (context, state) => const SearchScreen(), ), ], ), ], // 全局共享路由挂载在这里,所有分支都能访问,且路径不受分支影响 routes: [ movieDetailRoute, ], ), ], );
问题逐一解决说明
- 路径统一:电影详情路由属于
StatefulShellRoute的全局子路由,无论从首页还是搜索页跳转,路径始终为/movies/:id,不会带上/search这类分支前缀; - 路由重复:共享路由只需定义一次,后续扩展子路由也只需在抽离的配置中修改,无需在每个分支里重复编写;
- 递归跳转问题:在电影详情页跳转另一部电影时,使用根导航器上下文跳转,避免在当前分支导航栈中嵌套新的详情页:
// 在MovieDetailScreen中跳转新电影 GoRouter.of(context).push('/movies/$newMovieId'); // 或者直接指定根导航器key(更明确) _rootNavigatorKey.currentState?.pushNamed('/movies/$newMovieId');
关键注意点
不要把共享路由放在StatefulShellRoute外面,否则跳转时会完全替换掉包含底部菜单的Shell结构;而挂载在StatefulShellRoute的routes参数下,会在保留底部菜单的基础上,在其上方叠加详情页,符合需求。
内容的提问来源于stack exchange,提问作者Edgar Gataullin
相关产品推荐
相关产品推荐

