Flutter Bloc - 如何在提交失败时继续显示错误
Flutter Bloc - How to show keep showing error when submit is fail
我正在学习 bloc 并使用 equatable。
这是我的代码
login_state.dart
import 'package:equatable/equatable.dart';
import 'package:meta/meta.dart';
abstract class LoginState extends Equatable {
@override
List<Object> get props => [];
}
class LoginInitial extends LoginState {}
class LoginLoading extends LoginState {}
class LoginSuccess extends LoginState {
final Map token;
LoginSuccess({@required this.token});
}
class LoginFailure extends LoginState {
final Map error;
LoginFailure({@required this.error});
@override
List<Object> get props => null;
}
login_view
@override
Widget build(BuildContext context) {
final bool loading = _authStore.loading;
return BlocProvider(
create: (BuildContext context) => _loginBloc,
child: BlocListener<LoginBloc, LoginState>(
listener: (BuildContext context, state) {
if (state is LoginFailure) {
print("loginFailure is triggered with ${state.error}");
FlashAlert(context: context, message: state.error['message']).showFlash();
}
},
child: Scaffold(
resizeToAvoidBottomInset: true,
resizeToAvoidBottomPadding: true,
backgroundColor: Colors.white,
appBar: AppBar(
automaticallyImplyLeading: true,
),
body: Container(
padding: EdgeInsets.symmetric(horizontal: spacing(3)),
margin: EdgeInsets.only(top: spacing(2)),
child: widget.isLogin ? loginView() : registerView(),
),
floatingActionButton: FloatingActionButton(
backgroundColor: theme.primaryColor,
onPressed: () {
widget.isLogin ? handleLogin('') : handleRegister();
},
child: loading ? Progress() : Icon(EvaIcons.arrowIosForward),
),
),
));
}
我试过将 [error] 放在 get 道具上。
@override
List<Object> get props => [error];
问题是FlashAlert
只有运行 1次出现错误。如何继续使用 equatable 但在发生错误时继续触发 FlashAlert
?
谢谢。
----- 使用 blocbuilder 编辑 ---
@override
Widget build(BuildContext context) {
final bool loading = _authStore.loading;
return BlocProvider(
create: (BuildContext context) => _loginBloc,
child: BlocBuilder<LoginBloc, LoginState>(builder: (BuildContext context, state) {
if (state is LoginFailure) {
print("loginFailure is triggered with ${state.error}");
FlashAlert(context: context, message: state.error['message']).showFlash();
}
return Scaffold(
resizeToAvoidBottomInset: true,
resizeToAvoidBottomPadding: true,
backgroundColor: Colors.white,
appBar: AppBar(
automaticallyImplyLeading: true,
),
body: Container(
padding: EdgeInsets.symmetric(horizontal: spacing(3)),
margin: EdgeInsets.only(top: spacing(2)),
child: widget.isLogin ? loginView() : registerView(),
),
floatingActionButton: FloatingActionButton(
backgroundColor: theme.primaryColor,
onPressed: () {
widget.isLogin ? handleLogin('') : handleRegister();
},
child: state is LoginLoading ? Progress() : Icon(EvaIcons.arrowIosForward),
),
);
}),
);
}
return 错误:
VERBOSE-2:ui_dart_state.cc(157)] Unhandled Exception: setState() or markNeedsBuild() called during build.
This Overlay widget cannot be marked as needing to build because the framework is already in the process of building widgets. A widget can be marked as needing to be built during the build phase only if one of its ancestors is currently building. This exception is allowed because the framework builds parent widgets before children, which means a dirty descendant will always be built. Otherwise, the framework might not visit this widget during this build phase.
The widget on which setState() or markNeedsBuild() was called was:
Overlay-[LabeledGlobalKey<OverlayState>#21a25]
您正在使用 BlocListener,这就是您面临此问题的原因 error.BlocListener will only execute only only.
以下几行来自官方文档。
BlocListener is a Flutter widget which takes a BlocWidgetListener and
an optional Bloc and invokes the listener in response to state changes
in the bloc. It should be used for functionality that needs to occur
once per state change such as navigation, showing a SnackBar, showing
a Dialog, etc...
您可以使用 BlocBuilder 它会解决您的问题。
更新:
发生这种情况是因为当构建方法调用时您正在尝试显示 FlashAlert,因此您可以通过添加 1 微秒的等待时间来避免它。
调用以下方法而不是在 bloc 中执行。
void callme() async {
await Future.delayed(Duration(microseconds: 1));
if (state is LoginFailure) {
print("loginFailure is triggered with ${state.error}");
FlashAlert(context: context, message: state.error['message']).showFlash();
}
}
我正在学习 bloc 并使用 equatable。
这是我的代码
login_state.dart
import 'package:equatable/equatable.dart';
import 'package:meta/meta.dart';
abstract class LoginState extends Equatable {
@override
List<Object> get props => [];
}
class LoginInitial extends LoginState {}
class LoginLoading extends LoginState {}
class LoginSuccess extends LoginState {
final Map token;
LoginSuccess({@required this.token});
}
class LoginFailure extends LoginState {
final Map error;
LoginFailure({@required this.error});
@override
List<Object> get props => null;
}
login_view
@override
Widget build(BuildContext context) {
final bool loading = _authStore.loading;
return BlocProvider(
create: (BuildContext context) => _loginBloc,
child: BlocListener<LoginBloc, LoginState>(
listener: (BuildContext context, state) {
if (state is LoginFailure) {
print("loginFailure is triggered with ${state.error}");
FlashAlert(context: context, message: state.error['message']).showFlash();
}
},
child: Scaffold(
resizeToAvoidBottomInset: true,
resizeToAvoidBottomPadding: true,
backgroundColor: Colors.white,
appBar: AppBar(
automaticallyImplyLeading: true,
),
body: Container(
padding: EdgeInsets.symmetric(horizontal: spacing(3)),
margin: EdgeInsets.only(top: spacing(2)),
child: widget.isLogin ? loginView() : registerView(),
),
floatingActionButton: FloatingActionButton(
backgroundColor: theme.primaryColor,
onPressed: () {
widget.isLogin ? handleLogin('') : handleRegister();
},
child: loading ? Progress() : Icon(EvaIcons.arrowIosForward),
),
),
));
}
我试过将 [error] 放在 get 道具上。
@override
List<Object> get props => [error];
问题是FlashAlert
只有运行 1次出现错误。如何继续使用 equatable 但在发生错误时继续触发 FlashAlert
?
谢谢。
----- 使用 blocbuilder 编辑 ---
@override
Widget build(BuildContext context) {
final bool loading = _authStore.loading;
return BlocProvider(
create: (BuildContext context) => _loginBloc,
child: BlocBuilder<LoginBloc, LoginState>(builder: (BuildContext context, state) {
if (state is LoginFailure) {
print("loginFailure is triggered with ${state.error}");
FlashAlert(context: context, message: state.error['message']).showFlash();
}
return Scaffold(
resizeToAvoidBottomInset: true,
resizeToAvoidBottomPadding: true,
backgroundColor: Colors.white,
appBar: AppBar(
automaticallyImplyLeading: true,
),
body: Container(
padding: EdgeInsets.symmetric(horizontal: spacing(3)),
margin: EdgeInsets.only(top: spacing(2)),
child: widget.isLogin ? loginView() : registerView(),
),
floatingActionButton: FloatingActionButton(
backgroundColor: theme.primaryColor,
onPressed: () {
widget.isLogin ? handleLogin('') : handleRegister();
},
child: state is LoginLoading ? Progress() : Icon(EvaIcons.arrowIosForward),
),
);
}),
);
}
return 错误:
VERBOSE-2:ui_dart_state.cc(157)] Unhandled Exception: setState() or markNeedsBuild() called during build.
This Overlay widget cannot be marked as needing to build because the framework is already in the process of building widgets. A widget can be marked as needing to be built during the build phase only if one of its ancestors is currently building. This exception is allowed because the framework builds parent widgets before children, which means a dirty descendant will always be built. Otherwise, the framework might not visit this widget during this build phase.
The widget on which setState() or markNeedsBuild() was called was:
Overlay-[LabeledGlobalKey<OverlayState>#21a25]
您正在使用 BlocListener,这就是您面临此问题的原因 error.BlocListener will only execute only only.
以下几行来自官方文档。
BlocListener is a Flutter widget which takes a BlocWidgetListener and an optional Bloc and invokes the listener in response to state changes in the bloc. It should be used for functionality that needs to occur once per state change such as navigation, showing a SnackBar, showing a Dialog, etc...
您可以使用 BlocBuilder 它会解决您的问题。
更新:
发生这种情况是因为当构建方法调用时您正在尝试显示 FlashAlert,因此您可以通过添加 1 微秒的等待时间来避免它。
调用以下方法而不是在 bloc 中执行。
void callme() async {
await Future.delayed(Duration(microseconds: 1));
if (state is LoginFailure) {
print("loginFailure is triggered with ${state.error}");
FlashAlert(context: context, message: state.error['message']).showFlash();
}
}