想象一下我正在使用集团来处理网络请求。如果请求失败,则根据平台的不同,处理失败的方法也会有所不同。在我的Web应用程序上,我想将用户重定向到错误页面,而在IOS应用程序上,我想显示一个对话框。
由于只能使用bloc并共享它来处理业务逻辑,并且错误处理部分与业务逻辑无关,因此我们应该请ui部分来处理错误处理。
ui可以将错误回调发送到bloc,并且bloc将在发生错误时运行它。我们还可以通过在不同平台上发送不同的回调,以特定于平台的方式处理错误。
然后有两个问题:
在扑朔迷离中,我们只有在initState
生命周期方法之后才能访问bloc(因为我们从构建器上下文中获取bloc,而后者仅在initState
之后)。然后,我们只能在build方法中发送回调。
这样,我们将在每次重建时向bloc重复发送回调(这些重复没有意义)。
使用react,可以在诸如componentDidMount
之类的生命周期中完成一次初始化。
在颤抖中,我们如何达到只运行一次初始化的目标?
答案 0 :(得分:0)
这就是我们在团队中的处理方式:
首先,我们以如下方式构建主页(导航根):
Master
我们这样声明 @override
Widget build(BuildContext context) {
return BlocBuilder<SuspectEvent, SuspectState>(
bloc: _bloc,
builder: (context, state) {
if (state.cameras.isEmpty) _bloc.dispatch(GetCamerasEvent());
if (!_isExceptionHandled) {
_shouldHandleException(
hasException: state.hasException,
handleException: state.handleException);
}
return Scaffold(
...
(仍在主页上):
_shouldHandleException
在我们的街区,我们有:
_shouldHandleException(
{@required bool hasException, @required Exception handleException}) {
if (hasException) {
if (handleException is AuthenticationException) {
_isExceptionHandled = true;
SchedulerBinding.instance.addPostFrameCallback((_) async {
InfoDialog.showMessage(
context: context,
infoDialogType: DialogType.error,
text: 'Please, do your login again.',
title: 'Session expired')
.then((val) {
Navigator.popUntil(context, ModalRoute.withName('/'));
this._showLogin();
});
});
} else if (handleException is BusinessException) {
_isExceptionHandled = true;
SchedulerBinding.instance.addPostFrameCallback((_) async {
InfoDialog.showMessage(
context: context,
infoDialogType: DialogType.alert,
text: handleException.toString(),
title: 'Verify your fields')
.then((val) {
_bloc.dispatch(CleanExceptionEvent());
_isExceptionHandled = false;
});
});
} else {
_isExceptionHandled = true;
SchedulerBinding.instance.addPostFrameCallback((_) async {
InfoDialog.showMessage(
context: context,
infoDialogType: DialogType.error,
text: handleException.toString(),
title: 'Error on request')
.then((val) {
_bloc.dispatch(CleanExceptionEvent());
_isExceptionHandled = false;
});
});
}
}
}
在我们的错误处理(位于主页上)中,
@override
Stream<SuspectState> mapEventToState(SuspectEvent event) async* {
try {
if (event is GetCamerasEvent) {
... //(our logic)
yield (SuspectState.newValue(state: currentState)
..cameras = _cameras
..suspects = _suspects);
}
... //(other events)
} catch (error) {
yield (SuspectState.newValue(state: currentState)
..hasException = true
..handleException = error);
}
}
仅仅是InfoDialog
(来自Flutter),它位于任何路由的顶部。因此,只需要在根路由上调用警报即可。
答案 1 :(得分:0)
如果将BLoC封装在initState
方法中,则可以通过scheduleMicrotask
方法访问BLoC,以便它在initState
方法完成后运行:
@override
void initState() {
super.initState();
// Do initialization here.
scheduleMicrotask(() {
// Do stuff that uses the BLoC here.
});
}
您还可以签出this answer to a different question来概述简单BLoC模式,该模式仅在BLoC上直接调用异步方法,而不是将事件放入接收器。
这将允许这样的代码:
Future<void> login() {
try {
// Do the network stuff, like logging the user in or whatever.
Bloc.of(context).login(userController.text, emailController.text);
} on ServerNotReachableException {
// Redirect the user, display a prompt or change this
// widget's state to display an error. It's up to you.
}
}
答案 2 :(得分:0)
您可以使用superEnum包为Bloc创建状态和事件。(在这里,您可以通过执行以下操作为Error声明状态:
@Data(fields: [DataField<Error>('error')])
OrderLoadingFailedState,
(如果有人需要使用它的示例,请告诉我,我将向您显示示例)