【问题标题】:Flutter Bloc - How to show keep showing error when submit is failFlutter Bloc - 如何在提交失败时显示继续显示错误
【发布时间】:2020-09-03 04:56:05
【问题描述】:

我正在学习 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 props 上。

  @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),
          ),
        );
      }),
    );
  }

返回错误:

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]

【问题讨论】:

  • 显示您的 LoginBloc 文件
  • 一个快速的解决方法是 yield LoginLoading,然后 LoginFailure 强制更新,或添加特殊状态 LoginFailureBuffing 以保持逻辑。

标签: flutter bloc


【解决方案1】:

您正在使用 BlocListener,这就是您遇到此错误的原因。BlocListener 只会执行一次。

以下内容来自官方文档。

BlocListener 是一个 Flutter 小部件,它采用 BlocWidgetListener 和 一个可选的 Bloc 并调用侦听器以响应状态更改 在集团中。 它应该用于需要发生的功能 每个状态更改一次,例如导航,显示 SnackBar,显示 对话框等...

您可以使用BlocBuilder,它会解决您的问题。

更新:

发生这种情况是因为当时调用 build 方法时您正试图显示 FlashAlert,因此您可以通过添加 1 微秒的等待来避免它。

调用下面的方法而不是在块中做。

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

【讨论】:

  • 我添加了 if (state is LoginFailure) { print("loginFailure is triggered with ${state.error}"); FlashAlert(context: context, message: state.error['message']).showFlash(); } 到 BlocBuilder,它返回我 Failed assertion: line 3803 pos 12: '!_debugLocked': is not true.
  • 线程已使用 blocbuilder 更新。添加了错误。抱歉忘记粘贴了。
猜你喜欢
  • 2020-01-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-01
  • 2015-11-08
相关资源
最近更新 更多