Flutter GoRouter中跳转ShellRoute的replace方法异常问题求助
问题解决:GoRouter ShellRoute 未构建且页面未替换的问题
问题根源
- 路由结构错误:当前
ShellRoute与根路径/的GoRoute平级,/somepage1作为根级路由直接由根导航器处理,不会触发Shell组件的构建。 - 跳转逻辑未匹配路由结构:
context.replace('/somepage1')仅替换根导航栈页面,但由于目标路由不属于ShellRoute的嵌套范围,无法加载Shell。
解决方案
调整路由结构,给ShellRoute设置父路径,将somepage1、somepage2作为其嵌套子路由,确保跳转时触发Shell的构建并替换根页面。
修改后的完整代码
import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; void main() => runApp(const MyApp()); final GlobalKey<NavigatorState> rootNavKey = GlobalKey<NavigatorState>(); final GlobalKey<NavigatorState> shellNavKey = GlobalKey<NavigatorState>(); final GoRouter router = GoRouter( navigatorKey: rootNavKey, initialLocation: '/', routes: [ GoRoute( path: '/', pageBuilder: (context, state) => const NoTransitionPage(child: Home()), ), // 给ShellRoute设置父路径/app,作为嵌套路由的容器 ShellRoute( navigatorKey: shellNavKey, parentNavigatorKey: rootNavKey, routes: [ // 子路由使用相对路径,完整路径为/app/somepage1 GoRoute( path: 'somepage1', pageBuilder: (context, state) => const NoTransitionPage(child: SomePage1()), ), GoRoute( path: 'somepage2', pageBuilder: (context, state) => const NoTransitionPage(child: SomePage2()), ), ], builder: (context, state, child) => Shell(state: state, child: child), ), // 添加ShellRoute的入口路由,对应路径/app GoRoute( path: '/app', redirect: (context, state) => '/app/somepage1', ), ], ); class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp.router( routerConfig: router, ); } } class Shell extends StatelessWidget { Shell({super.key, required this.state, required this.child}) { print('Shell: ${state.location}'); } final GoRouterState state; final Widget child; @override Widget build(BuildContext context) { return Scaffold( body: Row( children: [ Container( width: 300.0, color: Colors.black, padding: const EdgeInsets.all(16), child: Column( children: [ ListTile( onTap: () => context.go('/app/somepage1'), title: const Text('Go to SomePage 1', style: TextStyle(color: Colors.white)), ), ListTile( onTap: () => context.go('/app/somepage2'), title: const Text('Go to SomePage 2', style: TextStyle(color: Colors.white)), ), ], ), ), Expanded(child: child), ], ), ); } } class Home extends StatelessWidget { const Home({super.key}); @override Widget build(BuildContext context) { return Scaffold( body: Center( child: InkWell( // 跳转到ShellRoute的入口路径,替换当前根页面 onTap: () => context.replace('/app/somepage1'), child: const Text('Click!'), ), ), ); } } class SomePage1 extends StatelessWidget { const SomePage1({super.key}); @override Widget build(BuildContext context) { return const Scaffold( body: Center( child: Text('Some Page 1'), ), ); } } class SomePage2 extends StatelessWidget { const SomePage2({super.key}); @override Widget build(BuildContext context) { return const Scaffold( body: Center( child: Text('Some Page 2'), ), ); } }
关键修改点
- 给
ShellRoute绑定父路径/app,子路由使用相对路径,确保/app/somepage1、/app/somepage2属于ShellRoute的嵌套范围。 - 修改Home页面的跳转目标为
/app/somepage1,使用context.replace替换根导航栈,移除原来的Home页面。 - 侧边栏的跳转路径更新为完整的
/app/somepage1、/app/somepage2,确保在Shell的嵌套导航器中切换页面。
实现效果
- 点击Home的"Click!"后,根导航栈中的Home页面被替换,
Shell组件和SomePage1同时加载。 - 侧边栏切换页面时,仅更新Shell右侧的内容区域,
Shell保持存在,符合嵌套路由的预期。
内容的提问来源于stack exchange,提问作者Jun
相关产品推荐
相关产品推荐

