在Modal Bottom Sheet中使用BlocProvider时找不到AuthBloc的问题
问题:Modal Bottom Sheet无法访问父级AuthBloc
我有一个嵌套在BlocProvider内部的Stateful Widget,包含GestureDetector:
@override Widget build(BuildContext context) { return RepositoryProvider.value( value: _authRepository, child: BlocProvider( create: (context) => AuthBloc(authRepository: AuthRepository()), child: Scaffold( body: GestureDetector( onTap: () { showSignInBottomSheet(context); }, ), ), ), ); }
点击时想弹出Modal Bottom Sheet,希望弹窗能访问之前创建的AuthBloc。按照建议用BlocProvider.value包裹弹窗builder部分,实现如下:
showSignInBottomSheet(BuildContext context) => showModalBottomSheet( context: context, isScrollControlled: true, backgroundColor: Colors.white, shape: const RoundedRectangleBorder( borderRadius: BorderRadius.vertical(top: Radius.circular(0.0)), ), builder: (context) { return BlocProvider.value( value: BlocProvider.of<AuthBloc>(context, listen: false), child: Container( padding: const EdgeInsets.only(top: 40), height: MediaQuery.of(context).size.height, child: Column( children: [ Padding( padding: const EdgeInsets.symmetric(horizontal: 15.0), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ springWidget(() { Navigator.of(context).pop(); }, const Icon( CupertinoIcons.xmark, size: 20, )), ], ), ), Expanded( child: Container( color: Colors.red, )), ], ))); });
但运行时出现错误:
BlocProvider.of() called with a context that does not contain a AuthBloc. No ancestor could be found starting from the context that was passed to BlocProvider.of<AuthBloc>().
问题原因
弹窗builder里的context是弹窗内部生成的新上下文,它的祖先树不包含外部的AuthBloc,直接在builder中调用BlocProvider.of<AuthBloc>(context)自然找不到对应的实例。
解决方法
方法1:提前获取AuthBloc实例再传入弹窗
在调用弹窗函数之前,先在能访问到Bloc的外部上下文里获取AuthBloc实例,再传递给弹窗:
- 修改GestureDetector的
onTap逻辑:
onTap: () { // 此处的context属于BlocProvider的子节点,能正确找到AuthBloc final authBloc = BlocProvider.of<AuthBloc>(context, listen: false); showSignInBottomSheet(context, authBloc); },
- 修改弹窗函数,接收传入的AuthBloc实例:
showSignInBottomSheet(BuildContext context, AuthBloc authBloc) => showModalBottomSheet( context: context, isScrollControlled: true, backgroundColor: Colors.white, shape: const RoundedRectangleBorder( borderRadius: BorderRadius.vertical(top: Radius.circular(0.0)), ), builder: (context) { return BlocProvider.value( value: authBloc, // 直接使用提前获取的实例 child: Container( // 原有布局代码保持不变 )); });
额外优化:复用Repository实例
你当前在BlocProvider的create方法中重新创建了AuthRepository(),但外部已经通过RepositoryProvider.value提供了实例,应该复用这个实例避免重复创建:
create: (context) => AuthBloc(authRepository: RepositoryProvider.of<AuthRepository>(context)),
内容的提问来源于stack exchange,提问作者Toby Yhs
相关产品推荐
相关产品推荐

