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

如何向Navigator传递Build Context以跨页面共享Bloc实例?

问题描述

我在练习Flutter+Bloc构建注册流程,应用为基础路径/registration设置了嵌套路由,且用BlocProvider包裹了MaterialApp。需求是在初始路由页面将手机号保存到Bloc状态,后续页面能读取该状态。

当前问题:初始页面能正常保存状态,但跳转到后续页面时会创建新的Bloc实例,导致无法访问已保存的状态。尝试向Navigator的builder传递现有Context但未成功,求重构方案解决MaterialPageRoute的builder生成新Build Context的问题。

现有代码

父级注册流程代码

class RegisterFlowState extends State<RegisterFlow> {
  final _navigatorKey = GlobalKey<NavigatorState>();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Navigator(
        key: _navigatorKey,
        initialRoute: 'register/phonenumber',
        onGenerateRoute: _onGenerateRoute,
      ),
    );
  }
}

Route _onGenerateRoute(RouteSettings settings) {
  WidgetBuilder builder;
  switch (settings.name) {
    case 'register/phonenumber':
      builder = (_) => const CollectPhonenumberPage();
      break;
    case 'register/otp':
      builder = (_) => const OtpPage();
      break;
    default:
      throw Exception('Invalid route: ${settings.name}');
  }
  return MaterialPageRoute<void>(builder: builder, settings: settings);
}

初始页面(保存状态并跳转)代码

ElevatedButton(
  onPressed: () {
    phoneNumberBloc.add(UpdatePhoneNumberEvent(phoneController.text));
    Navigator.of(context).pushReplacementNamed('register/otp');
  },
  child: const Text('保存'),
)

后续页面(读取状态)代码

BlocBuilder<PhoneNumberBloc, PhoneNumberState>(
  builder: (context, state) => Text('${state.data}'),
)
解决方案

问题核心是嵌套路由的MaterialPageRoute会创建独立的Context分支,导致页面无法共享上层已有的Bloc实例。通过在路由构建时用BlocProvider.value传递已有的Bloc实例,可确保所有页面复用同一个Bloc,避免实例重建。

具体修改步骤:

  1. 修改RegisterFlowState的build方法:
    在嵌套Navigator的路由生成逻辑中,先获取上层的Bloc实例,再用BlocProvider.value包裹页面,传递该实例:

    class RegisterFlowState extends State<RegisterFlow> {
      final _navigatorKey = GlobalKey<NavigatorState>();
    
      @override
      Widget build(BuildContext context) {
        // 获取上层已初始化的Bloc实例
        final phoneNumberBloc = BlocProvider.of<PhoneNumberBloc>(context);
        return Scaffold(
          body: Navigator(
            key: _navigatorKey,
            initialRoute: 'register/phonenumber',
            onGenerateRoute: (settings) {
              Widget page;
              switch (settings.name) {
                case 'register/phonenumber':
                  page = const CollectPhonenumberPage();
                  break;
                case 'register/otp':
                  page = const OtpPage();
                  break;
                default:
                  throw Exception('Invalid route: ${settings.name}');
              }
              // 用BlocProvider.value包裹页面,确保复用同一个Bloc实例
              return MaterialPageRoute(
                builder: (_) => BlocProvider.value(
                  value: phoneNumberBloc,
                  child: page,
                ),
                settings: settings,
              );
            },
          ),
        );
      }
    }
    
  2. 优化初始页面的Bloc调用方式:
    避免直接持有Bloc实例,改用BlocProvider.of从Context获取,更符合Bloc规范:

    ElevatedButton(
      onPressed: () {
        final phoneNumberBloc = BlocProvider.of<PhoneNumberBloc>(context);
        phoneNumberBloc.add(UpdatePhoneNumberEvent(phoneController.text));
        Navigator.of(context).pushReplacementNamed('register/otp');
      },
      child: const Text('保存'),
    )
    

这样修改后,所有嵌套路由页面都会复用同一个Bloc实例,后续页面就能正常读取初始页面保存的状态。

内容的提问来源于stack exchange,提问作者bengü thon mai mochi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 18:23:08