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();
    }
  }