You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

GoRouter StatefulShellRoute.indexedStack导航崩溃问题求助

问题解决:GoRouter StatefulShellRoute.indexedStack导航与状态传递问题

问题核心

  1. 无法直接导航到VistaGeneralEmpresa:StatefulShellRoute本身不支持设置路由名称或路径,只能通过其内部分支的初始路由进入
  2. 切换分支崩溃:切换到VistaCaja/VistaAjustes时,分支路由的state.extra为null,导致无法获取Empresa对象

解决方案

1. 给Shell路由添加入口GoRoute

通过在StatefulShellRoute外层包裹一个GoRoute,设置专属的名称和路径,实现直接导航到VistaGeneralEmpresa,同时将Empresa传递到Shell的根组件。

2. 共享Empresa对象到所有分支

不再依赖路由extra传递Empresa,而是在VistaGeneralEmpresa中通过InheritedWidget将Empresa共享给所有子分支页面,确保切换分支时每个页面都能获取到有效对象。

修改后的代码

1. 路由配置

GoRoute(
  name: 'vistaGeneralEmpresa',
  path: '/vistaGeneralEmpresa',
  builder: (context, state) {
    // 从入口路由的extra获取Empresa
    final Empresa empresa = state.extra as Empresa;
    return StatefulShellRoute.indexedStack(
      builder: (context, shellState, navigationShell) {
        return VistaGeneralEmpresa(
          empresa: empresa,
          navigationShell: navigationShell,
        );
      },
      branches: <StatefulShellBranch>[
        StatefulShellBranch(
          navigatorKey: _rootNavigatorInicio,
          routes: <RouteBase>[
            GoRoute(
              name: 'inicioEmpresa',
              path: 'inicioEmpresa', // 改为相对路径,依赖外层的/vistaGeneralEmpresa
              builder: (context, state) {
                // 从共享的Provider获取Empresa
                final empresa = EmpresaProvider.of(context).empresa;
                return VistaInicioEmpresa(empresa: empresa);
              },
              routes: [
                GoRoute(
                  name: 'gestionInventario',
                  path: 'gestionInventario',
                  builder: (context, state) {
                    final empresa = EmpresaProvider.of(context).empresa;
                    return VistaGeneralInventario(empresa);
                  }),
                GoRoute(
                  name: 'historial',
                  path: 'historial',
                  builder: (context, state) {
                    final empresa = EmpresaProvider.of(context).empresa;
                    return VistaHistorial(empresa: empresa);
                  }),
                GoRoute(
                  name: 'estadisticas',
                  path: 'estadisticas',
                  builder: (context, state) {
                    final empresa = EmpresaProvider.of(context).empresa;
                    return VistaEstadisticas(empresa: empresa);
                  }),
              ]),
        ),
        StatefulShellBranch(
          navigatorKey: _rootNavigatorCaja,
          routes: <RouteBase>[
            GoRoute(
              path: 'caja', // 改为相对路径,与外层路由组合为/vistaGeneralEmpresa/caja
              builder: (context, state) {
                final empresa = EmpresaProvider.of(context).empresa;
                return VistaCaja(empresa: empresa);
              },
              routes: []),
          ],
        ),
        StatefulShellBranch(
          navigatorKey: _rootNavigatorAjustes,
          routes: <RouteBase>[
            GoRoute(
              path: 'ajustes', // 改为相对路径,与外层路由组合为/vistaGeneralEmpresa/ajustes
              builder: (context, state) {
                final empresa = EmpresaProvider.of(context).empresa;
                return VistaAjustesEmpresa(empresa: empresa);
              },
              routes: [],
            ),
          ],
        ),
      ],
    );
  },
),

2. 实现Empresa共享的InheritedWidget

class EmpresaProvider extends InheritedWidget {
  final Empresa empresa;

  const EmpresaProvider({
    super.key,
    required this.empresa,
    required super.child,
  });

  // 提供便捷的获取方法
  static EmpresaProvider of(BuildContext context) {
    final provider = context.dependOnInheritedWidgetOfExactType<EmpresaProvider>();
    assert(provider != null, '未找到EmpresaProvider,请确保在父组件中包裹');
    return provider!;
  }

  @override
  bool updateShouldNotify(EmpresaProvider oldWidget) {
    return empresa != oldWidget.empresa;
  }
}

3. 修改VistaGeneralEmpresa,包裹Provider

class VistaGeneralEmpresa extends StatefulWidget {
  final Empresa empresa;
  final StatefulNavigationShell navigationShell;

  const VistaGeneralEmpresa({
    super.key,
    required this.empresa,
    required this.navigationShell,
  });

  @override
  State<VistaGeneralEmpresa> createState() => _VistaGeneralEmpresaState();
}

class _VistaGeneralEmpresaState extends State<VistaGeneralEmpresa> {
  int selectedIndex = 0;

  void _goBranch(int index) {
    widget.navigationShell.goBranch(
      index,
      initialLocation: index == widget.navigationShell.currentIndex,
    );
  }

  @override
  Widget build(BuildContext context) {
    // 用EmpresaProvider包裹整个页面,让所有子分支都能获取到Empresa
    return EmpresaProvider(
      empresa: widget.empresa,
      child: Scaffold(
        body: SizedBox(
          width: double.infinity,
          height: double.infinity,
          child: widget.navigationShell,
        ),
        bottomNavigationBar: GNav(
          onTabChange: (value) {
            setState(() {
              selectedIndex = value;
              _goBranch(selectedIndex);
            });
          },
          selectedIndex: selectedIndex,
          gap: 8,
          backgroundColor: Colors.amberAccent,
          color: const Color.fromARGB(255, 70, 70, 70),
          activeColor: Colors.black,
          padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 20),
          tabs: const [
            GButton(icon: Icons.home, text: 'Inicio'),
            GButton(icon: Icons.inventory, text: 'Caja'),
            GButton(icon: Icons.settings, text: 'Ajustes')
          ],
        ),
      ),
    );
  }
}

4. 修改导航调用代码

void _navigateToVistaEmpresa(BuildContext context) {
  // 直接导航到Shell的入口路由
  context.goNamed("vistaGeneralEmpresa", extra: empresa);
}

关键说明

  • 外层GoRoute作为Shell的入口,解决了无法直接导航到VistaGeneralEmpresa的问题
  • 使用InheritedWidget共享Empresa,避免了切换分支时extra为null的崩溃问题,同时让所有子页面无需重复传递Empresa参数
  • 分支路由路径改为相对路径后,既支持通过底部导航切换,也支持直接通过/vistaGeneralEmpresa/caja这类路径访问对应分支

内容的提问来源于stack exchange,提问作者Dox

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 07:47:04