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

在go_router v5.0的redirect方法中无法访问注入的BLoC

问题:Flutter Bloc + GoRouter 多表单页面的路由重定向问题

使用flutter_bloc和go_router实现两页多步骤表单,通过ShellRoute为两个路由共享同一个MultiFormBloc实例。但在step2路由的redirect方法中,无法从BuildContext获取到这个Bloc,导致无法根据step1的完成状态判断是否重定向回step1(防止用户直接输入/step2访问)。

用户的路由配置代码:

...

ShellRoute(
  builder: (context, state, child) {
    // 通过ShellRoute为两个路由提供同一个MultiFormBloc实例
    return BlocProvider(
      create: (context) => MultiFormBloc(),
      child: child,
    );
  },
  routes: [
    GoRoute(
      name: 'step1',
      path: 'step1',
      builder: (context, state) => Step1(),
      routes: [
        GoRoute(
          name: 'step2',
          path: 'step2',
          builder: (context, state) => Step2(),
          redirect: (context, state) {
            // 报错:无法获取MultiFormBloc,context中未注入
            if (context.read<MultiFormBloc>().state.step1Value == null) {
              return '/step1';
            }
            return null;
          },
        ),
      ],
    ),
  ],
),

...

解决方案

原因说明

redirect方法的执行时机早于ShellRoute的builder构建,此时ShellRoute中提供的Bloc还未被注入到context中,所以无法直接读取。

方法1:将Bloc提升到全局层级提供

如果这个MultiFormBloc仅用于该多步骤表单流程,可将其提供在GoRouter的父级(比如MaterialApp的上层),这样整个路由树的context都能访问到:

// 在main.dart或路由配置的上层
BlocProvider(
  create: (context) => MultiFormBloc(),
  child: MaterialApp.router(
    routerConfig: _router,
  ),
)

之后在step2的redirect方法中就能正常使用context.read<MultiFormBloc>()判断状态。

方法2:在Step2页面内部处理重定向

放弃在路由配置的redirect中处理,改为进入Step2页面后检查状态:

class Step2 extends StatefulWidget {
  @override
  State<Step2> createState() => _Step2State();
}

class _Step2State extends State<Step2> {
  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addPostFrameCallback((_) {
      final bloc = context.read<MultiFormBloc>();
      if (bloc.state.step1Value == null) {
        context.goNamed('step1');
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    // Step2页面内容
    return Scaffold(body: ...);
  }
}

这种方式更符合ShellRoute的Bloc作用域,因为进入Step2页面时,ShellRoute的builder已经完成,context中已经注入了MultiFormBloc。

方法3:使用GoRouter的refreshListenable监听Bloc状态

通过Bloc的stream创建Listenable,让GoRouter能感知状态变化并触发重定向:

// 创建一个监听Bloc状态的Listenable
class MultiFormListenable extends ChangeNotifier {
  MultiFormListenable(this.bloc) {
    _subscription = bloc.stream.listen((_) => notifyListeners());
  }

  final MultiFormBloc bloc;
  late final StreamSubscription _subscription;

  @override
  void dispose() {
    _subscription.cancel();
    super.dispose();
  }
}

// 在路由配置中使用
final _bloc = MultiFormBloc();
final _router = GoRouter(
  refreshListenable: MultiFormListenable(_bloc),
  routes: [
    ShellRoute(
      builder: (context, state, child) {
        return BlocProvider.value(
          value: _bloc,
          child: child,
        );
      },
      routes: [
        GoRoute(
          name: 'step1',
          path: '/step1',
          builder: (context, state) => Step1(),
          routes: [
            GoRoute(
              name: 'step2',
              path: 'step2',
              builder: (context, state) => Step2(),
              redirect: (context, state) {
                if (_bloc.state.step1Value == null) {
                  return '/step1';
                }
                return null;
              },
            ),
          ],
        ),
      ],
    ),
  ],
);

这种方式直接持有Bloc实例,不需要依赖context,同时能在状态变化时自动触发路由刷新。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 15:55:20