如何向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,避免实例重建。
具体修改步骤:
修改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, ); }, ), ); } }优化初始页面的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
相关产品推荐
相关产品推荐

