在对话框中使用 BLoC:找不到正确的提供程序
Posted
技术标签:
【中文标题】在对话框中使用 BLoC:找不到正确的提供程序【英文标题】:Using BLoC in a dialog: Could not find the correct Provider 【发布时间】:2021-02-24 18:56:05 【问题描述】:我正在尝试使用块来管理对话框的内容。我对 Flutter 还很陌生。
页面定义为:
@override
Widget build(BuildContext context)
return Scaffold(
appBar: AppBar(
title: Text("Business Region Manager"),
),
body: MultiBlocProvider(
providers: [
BlocProvider(
create: (context) =>
EntityModifyBloc(repository: widget.repository),
),
BlocProvider(
create: (context) => EntityBloc(
repository: widget.repository,
modifyBloc: BlocProvider.of<EntityModifyBloc>(context)),
),
BlocProvider(
create: (context) => BusinessRegionBloc(repository: widget.repository),
),
],
child: Center(
child: BusinessRegionPage(widget.business),
),
));
在 BusinessRegionPage 内部,我使用了 EntityBloc 和 EntityModifyBloc,并且至少我认为我是正确的。 该页面有一个回调,在触发时会调用一个方法:
void onAddBusinessRegion()
showDialog(context: context,
barrierDismissible: false,
builder: (BuildContext context)
return BusinessRegionDialog(
positiveText: "Ok",
onPositive: onPositive,
negativeText: 'Cancel',
onNegative: onNegative,
businessId: widget.business.id,
);
);
BusinessRegionDialog 是一个有状态的小部件,状态实现构建是:
@override
Widget build(BuildContext context)
return BlocBuilder<BusinessRegionBloc, BusinessRegionState>(builder: (context, state)
if (state is BusinessRegionEmpty)
BlocProvider.of<BusinessRegionBloc>(context).add(GetBusinessRegions(widget.businessId));
if (state is BusinessRegionError)
return Center(
child: Text('Busines Region Error'),
);
if (state is BusinessRegionLoaded)
return Center(
child: Text('BusinessRegionLoaded'),
);
return Center(
child: CircularProgressIndicator(),
);
);
当回调被触发时,我收到消息:
错误:在此 BlocBuilder
这可能是因为您使用了不包含提供程序的BuildContext
您的选择。
我假设在调用 ShowDialog(context) 时,上下文与传递给 build 的上下文相同?我通过在 showDialog 调用之前和 BusinessRegionPage 上的构建实现之后打印上下文的 hashCode 来检查这个假设,
错误消息中的一个建议是:
Widget build(BuildContext context)
return Provider<Example>(
create: (_) => Example(),
builder: (context)
return Text(context.watch<Example>()),
),
所以我尝试了:
void onAddBusinessRegion()
print("OnAddCallback: " + context.hashCode.toString());
BusinessRegionClient brClient = BusinessRegionClient(client: http.Client());
BusinessRegionRepository brRepository =
BusinessRegionRepository(client: brClient);
showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context)
return Provider<BusinessRegionBloc>(
create: (_) => BusinessRegionBloc(repository: brRepository),
builder: (context)
return BusinessRegionDialog(
positiveText: "Ok",
onPositive: onPositive,
negativeText: 'Cancel',
onNegative: onNegative,
businessId: widget.business.id,
);
);
);
IDE 告诉我: 参数类型“BusinessRegionDialog Function(BuildContext)”不能分配给参数类型“Widget Function(BuildContext, Widget)”。
我显然不明白一些事情。我要做的就是用我的存储库中的 Future 信息填充一个对话框。任何指导将不胜感激。
【问题讨论】:
【参考方案1】:多亏了so条目,我终于弄明白了:
Flutter: bloc, how to show an alert dialog
这里的答案是使用堆栈让对话框和页面共存,并在侦听器具有正确状态时显示对话框。答案使用 StatelessWidget 来管理,就答案而言,是 SnackBar。为了能够向 bloc 添加事件,我使用了 StatefulWidget。
@override
Widget build(BuildContext context)
return Scaffold(
appBar: AppBar(
title: Text("Business Region Manager"),
),
body: MultiBlocProvider(
providers: [
BlocProvider(
create: (context) => EntityModifyBloc(
repository: xbrRepository), //widget.repository),
),
BlocProvider(
create: (context) => EntityBloc(
repository: xbrRepository, //widget.repository,
modifyBloc: BlocProvider.of<EntityModifyBloc>(context)),
),
BlocProvider(
create: (context) => BusinessRegionDialogBloc(
repository: xbrRepository),
),
],
child: Stack(children: [
BusinessRegionDialogManager(widget.business.id),
Center(child: BusinessRegionPage(widget.business)),
]),
));
class BusinessRegionDialogManager extends StatefulWidget
final int businessId;
BusinessRegionDialogManager(this.businessId);
State<BusinessRegionDialogManager> createState() =>
_BusinessRegionDialogManagerState();
类 _BusinessRegionDialogManagerState 扩展状态
// Callback functions from the dialog so can have access to
// BusinessRegionDialogBloc
void xnPositive(List<Region> addedRegions)
BlocProvider.of<BusinessRegionDialogBloc>(context)
.add(AddBusinessRegions(addedRegions, widget.businessId));
void xnNegative()
@override
Widget build(BuildContext context)
return BlocListener<BusinessRegionDialogBloc, BusinessRegionDialogState>(
listener: (context, state)
if (state is RegionDialogLoaded)
showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context)
return BusinessRegionDialog(
onPositive: xnPositive,
onNegative: xnNegative,
regions: state.regions,
);
)
,
child: Container(),
);
【讨论】:
【参考方案2】:i solved it as like this
你要做的是创建一个 BlocTypeA 的提供者将它传递给孩子。创建一个 带有另一个上下文的对话框2 使用 provider.value 然后传递 bloc 使用 context2 构建它的子组件并在子小部件内部使用先前的上下文访问 bloc .read with BlocTypeA... 因此它解决了
【讨论】:
以上是关于在对话框中使用 BLoC:找不到正确的提供程序的主要内容,如果未能解决你的问题,请参考以下文章
MultiBlocProvider 未实例化所有 bloc 提供程序 - 如何正确使用 MultiBlocProvider?