【问题标题】:Flutter bloc listener not listening to state changesFlutter bloc 监听器不监听状态变化
【发布时间】:2021-02-17 02:50:15
【问题描述】:

我正在使用flutter_bloc 库来创建验证码页面。这是我尝试做的。

class PhonePage extends StatelessWidget {
  static Route route() {
    return MaterialPageRoute<void>(builder: (_) => PhonePage());
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: BlocProvider(
        create: (_) =>
            ValidationCubit(context.repository<AuthenticationRepository>()),
        child: PhoneForm(),
      ),
    );
  }
}

class PhoneForm extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return BlocConsumer<ValidationCubit, ValidationState>(
      listener: (context, state) {
        print('Listener has been called');
        if (state.status.isSubmissionFailure) {
          _showVerificationError(context);
        } else if (state.status.isSubmissionSuccess) {
          _showVerificationSuccess(context);
        }
      },
      builder: (context, state) {
        return Container(
          child: SingleChildScrollView(
            child: Padding(
              padding: EdgeInsets.all(16.0),
              child: Column(
                mainAxisSize: MainAxisSize.max,
                crossAxisAlignment: CrossAxisAlignment.center,
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                children: [
                  _HeaderAndTitle(),
                  _VerificationInput(),
                  _VerifyButton()
                ],
              ),
            ),
          ),
        );
      },
    );
  }

  void _showVerificationError(context) {
    Scaffold.of(context)
      ..hideCurrentSnackBar()
      ..showSnackBar(const SnackBar(content: Text('Validation error')));
  }

  void _showVerificationSuccess(context) {
    Scaffold.of(context)
      ..hideCurrentSnackBar()
      ..showSnackBar(const SnackBar(
        content: Text('Validation Success'),
        backgroundColor: Colors.green,
      ));
  }
}

...

class _VerifyButton extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return BlocBuilder<ValidationCubit, ValidationState>(
        builder: (context, state) {
      return RaisedButton.icon(
          color: Colors.blue,
          padding: EdgeInsets.symmetric(horizontal: 38.0, vertical: 12.0),
          textColor: Colors.white,
          icon: state.status.isSubmissionInProgress
              ? Icon(FontAwesomeIcons.ellipsisH)
              : Icon(null),
          label: Text(state.status.isSubmissionInProgress ? '' : 'Verify',
              style: TextStyle(fontSize: 16.0)),
          shape:
              RoundedRectangleBorder(borderRadius: BorderRadius.circular(25)),
          onPressed: state.status.isValid
              ? () => context.bloc<ValidationCubit>().verifyCode()
              : null);
    });
  }
}

现在 verifyCode() 函数是一个在 ValidationCubit 中定义的异步函数。它发出状态设置为加载、成功和失败的状态。然而,听众不会接受这些变化并显示小吃店。我想不通为什么?我也在使用 Flutter_bloc 文档中建议的 Formz 库。这是 verifyCode 部分。

Future<void> verifyCode() async {
    if (!state.status.isValidated) return;
    emit(state.copyWith(status: FormzStatus.submissionInProgress));
    try {
      // send validation code to server here
      await _authenticationRepository.loginWithEmailAndPassword(
          email: 'email@email.com', password: '12');
      emit(state.copyWith(status: FormzStatus.submissionSuccess));
    } on Exception {
      emit(state.copyWith(status: FormzStatus.submissionFailure));
    }
  }

验证码模型如下:

class ValidationState extends Equatable {
  final VerificationCode verificationCode;
  final FormzStatus status;

  const ValidationState({this.verificationCode, this.status});

  @override
  List<Object> get props => [verificationCode];

  ValidationState copyWith(
      {VerificationCode verificationCode, FormzStatus status}) {
    return ValidationState(
        verificationCode: verificationCode ?? this.verificationCode,
        status: status ?? this.status);
  }
}

而验证状态类是:

class ValidationState extends Equatable {
  final VerificationCode verificationCode;
  final FormzStatus status;

  const ValidationState({this.verificationCode, this.status});

  @override
  List<Object> get props => [verificationCode];

  ValidationState copyWith(
      {VerificationCode verificationCode, FormzStatus status}) {
    return ValidationState(
        verificationCode: verificationCode ?? this.verificationCode,
        status: status ?? this.status);
  }
}

【问题讨论】:

  • 我不知道有哪些集团国家。我知道当状态从另一个状态改变时会触发“listner”..
  • 是否打印 print('Listener has been called'); ??
  • 请添加您已定义的州类或州。
  • @xbadal 我已经更新它以包含状态和模型类。单击按钮时,它不会打印“已调用侦听器”。
  • 你没有屈服状态。所以基本上状态没有改变。这就是它不打印的原因。

标签: flutter flutter-bloc


【解决方案1】:

我认为问题出在你的状态类。

listener 与 BlocBuilder 中的 builder 不同,每次状态更改(不包括初始状态)只调用一次,并且是一个 void 函数。

Cubit 每次发出新状态时都会与前一个状态进行比较,如果它们“不同”,则触发监听函数。

在您的情况下,您使用的 Equatable 仅具有 verificationCode 作为 props,这意味着当比较两个状态时,仅测试 verificationCodes。这样 BLoC 消费者认为两个状态相等,不会再次触发监听函数。

如果您检查您的 verifyCode() 函数,唯一更改的参数是 status

为了解决这个问题,请将status 属性添加到您的状态类中的props 列表中。

  @override
  List<Object> get props => [this.verificationCode, this.status];

【讨论】:

    【解决方案2】:

    如果您想更新相同的状态,只需在调用更新状态之前添加一个状态 像这样 如果您想再次更新“加载”状态,请在此之前调用“加载”状态,而不是调用“加载”状态,以便 BlocListener 和 BlocBuilder 会监听它

    已编辑 为此,我已将 bloc 更改为 cubit ,并且 cubit 可以连续发出相同的状态,并且 bloclistener 和 blocbuilder 可以听到它

    【讨论】:

    • 请在您的回答中分享一些简短的示例代码
    • 尝试使用cubit它可以发出相同的状态并且bloclistener和blocbuilder可以听它
    猜你喜欢
    • 2020-03-26
    • 2022-10-23
    • 2020-06-15
    • 2020-03-27
    • 2020-04-29
    • 2017-05-31
    • 1970-01-01
    • 2019-08-10
    • 1970-01-01
    相关资源
    最近更新 更多