Flutter 集团监听器不监听状态变化
Flutter bloc listener not listening to state changes
我正在使用 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是:
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。
listener is only called once for each state change (NOT including the initial state) unlike builder in BlocBuilder and is a void function.
每当 Cubit 发出新状态时,它都会与前一个状态进行比较,如果它们“不同”,则触发侦听器功能。
在您的情况下,您使用的 Equatable 只有 verificationCode
作为 props
,这意味着当比较两个状态时,只测试 verificationCode
。这样BLoC消费者就认为两个状态是相等的,不会再触发监听函数。
如果您检查 verifyCode()
函数,唯一变化的参数是 status
。
为了解决这个问题,请将 status
属性 添加到您所在州 class 的 props
列表中。
@override
List<Object> get props => [this.verificationCode, this.status];
如果你想更新相同的状态,只需在调用你的更新状态之前添加一个状态
像这样
如果您想再次更新 'Loaded' 状态,请在此之前调用 'Loading' 状态,而不是调用 'Loaded' 状态,以便 BlocListener 和 BlocBuilder 将收听它
已编辑
为此,我已将 bloc 更改为 cubit,cubit 可以连续发出相同的状态,bloclistener 和 blocbuilder 可以收听它
我正在使用 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是:
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。
listener is only called once for each state change (NOT including the initial state) unlike builder in BlocBuilder and is a void function.
每当 Cubit 发出新状态时,它都会与前一个状态进行比较,如果它们“不同”,则触发侦听器功能。
在您的情况下,您使用的 Equatable 只有 verificationCode
作为 props
,这意味着当比较两个状态时,只测试 verificationCode
。这样BLoC消费者就认为两个状态是相等的,不会再触发监听函数。
如果您检查 verifyCode()
函数,唯一变化的参数是 status
。
为了解决这个问题,请将 status
属性 添加到您所在州 class 的 props
列表中。
@override
List<Object> get props => [this.verificationCode, this.status];
如果你想更新相同的状态,只需在调用你的更新状态之前添加一个状态 像这样 如果您想再次更新 'Loaded' 状态,请在此之前调用 'Loading' 状态,而不是调用 'Loaded' 状态,以便 BlocListener 和 BlocBuilder 将收听它
已编辑 为此,我已将 bloc 更改为 cubit,cubit 可以连续发出相同的状态,bloclistener 和 blocbuilder 可以收听它