我是Bloc的新手,我注意到当一个状态改变时,它会为一个状态改变多次,让我解释一下,例如我有这样的设置,在我的login_page.dart
上,我有一个BlocListener
,当登录操作成功时,它基本上显示一个snackbar并导航到另一个页面:
BlocListener<AuthBloc, AuthState>(
listenWhen: (previous, current) => previous != current,
listener: (context, state) {
dev.log('listener login page: $state');
if (state is AuthLoadingState) {
loadingDialog(context);
} else if (state is AuthLoadedState) {
Navigator.of(context).pushReplacement(
MaterialPageRoute(
builder: (context) => const HomePage(),
),
);
showSnackBar(
message: 'Logged in successfully', isError: false);
} else if (state is AuthErrorState) {
Navigator.of(context).pop();
showSnackBar(message: state.message, isError: true);
}
},
child: AuthButtonWidget(
formKey: _formKey,
onPressed: () {
if (_formKey.currentState!.validate()) {
BlocProvider.of<AuthBloc>(context).add(
LogInWithEmailAndPasswordEvent(
email: _emailController.text,
password: _passwordController.text,
),
);
}
},
text: 'Log In',
),
),
在我的home_page.dart
上,我有一个BlocConsumer
,它监听一个事件,显示一个snackbar,并在按下按钮(注销)时导航回登录页面:
BlocConsumer<AuthBloc, AuthState>(
listenWhen: (previous, current) => previous != current,
listener: (context, state) {
dev.log('listener home page: $state');
if (state is AuthLoadingState) {
loadingDialog(context);
} else if (state is AuthLoggedOutState) {
Navigator.of(context).pushReplacement(
MaterialPageRoute(
builder: (context) => const LoginPage(),
),
);
showSnackBar(message: 'Logged out successfully', isError: false);
} else if (state is AuthErrorState) {
Navigator.of(context).pop();
showSnackBar(message: state.message, isError: true);
}
},
buildWhen: (previous, current) => previous != current,
builder: (context, state) {
dev.log('builder home page: $state');
if (state is AuthLoadedState) {
return const HomePageWidget();
} else if (state is AuthErrorState) {
return const Center(
child: Text('AuthErrorState'),
);
} else {
return const HomePageWidget();
}
},
);
HomePageWidget()
只是一个带有浮动操作按钮的列,用于断开用户连接。更多信息,请看我的博客:
class AuthBloc extends Bloc<AuthEvent, AuthState> {
final SignUpWithEmailAndPasswordUsecase signUpWithEmailAndPassword;
final LogInWithEmailAndPasswordUsecase logInWithEmailAndPassword;
final LogOutUsecase logOut;
AuthBloc(
this.signUpWithEmailAndPassword,
this.logInWithEmailAndPassword,
this.logOut,
) : super(AuthInitial()) {
on<AuthEvent>((event, emit) async {
if (event is SignUpWithEmailAndPasswordEvent) {
emit(AuthLoadingState());
final failureOrUnit = await signUpWithEmailAndPassword(
email: event.email,
password: event.password,
name: event.name,
);
emit(_mapFailureOrPostsState(either: failureOrUnit));
} else if (event is LogInWithEmailAndPasswordEvent) {
emit(AuthLoadingState());
final failureOrUnit = await logInWithEmailAndPassword(
email: event.email,
password: event.password,
);
emit(_mapFailureOrPostsState(either: failureOrUnit));
} else if (event is LogOutEvent) {
emit(AuthLoadingState());
final failureOrUnit = await logOut();
emit(_mapFailureOrPostsState(
either: failureOrUnit,
isLogOut: true,
));
}
});
}
}
AuthState _mapFailureOrPostsState({
required Either<Failure, Unit> either,
bool isLogOut = false,
}) {
return either.fold(
(failure) => AuthErrorState(message: _mapFailureToMessage(failure)),
(_) {
if (isLogOut) {
return AuthLoggedOutState();
} else {
return AuthLoadedState();
}
},
);
}
String _mapFailureToMessage(Failure failure) {
if (failure is SignUpWithEmailAndPasswordFailure) {
switch (failure.code) {
case 'email-already-in-use':
return EMAIL_ALREADY_IN_USE_FAILURE_MESSAGE;
case 'invalid-email':
return INVALID_EMAIL_FAILURE_MESSAGE;
case 'operation-not-allowed':
return OPERATION_NOT_ALLOWED_FAILURE_MESSAGE;
case 'weak-password':
return WEAK_PASSWORD_FAILURE_MESSAGE;
default:
return SIGN_UP_WITH_EMAIL_AND_PASSWORD_FAILURE_MESSAGE;
}
} else if (failure is LogInWithEmailAndPasswordFailure) {
switch (failure.code) {
case 'invalid-email':
return INVALID_EMAIL_FAILURE_MESSAGE;
case 'user-disabled':
return USER_IS_DISABLED_FAILURE_MESSAGE;
case 'user-not-found':
return USER_NOT_FOUND_FAILURE_MESSAGE;
case 'wrong-password':
return WRONG_PASSWORD_FAILURE_MESSAGE;
default:
return LOG_IN_WITH_EMAIL_AND_PASSWORD_FAILURE_MESSAGE;
}
} else if (failure is LogOutFailure) {
return LOG_OUT_FAILURE_MESSAGE;
} else if (failure is OfflineFailure) {
return OFFLINE_FAILURE_MESSAGE;
} else if (failure is EmptyCacheFailure) {
return EMPTY_CACHE_FAILURE_MESSAGE;
} else {
return UNEXPECTED_FAILURE_MESSAGE;
}
}
当我按下按钮时,它工作得很好,但它显示了多个小吃条(例如,当我注销时,它可以显示5个小吃条告诉我“注销成功”一个接一个),我有两个问题,为什么这些小吃条显示多倍,我可以改变我的代码来删除bug?
1条答案
按热度按时间l7wslrjt1#
我认为这是因为你在你的主注册你的Bloc(它可以是你的主。 dart 或你的主应用程序的类)纠正我,如果我错了。
如果我们把它登记在主要的地方,这个集团就会变成一个全球性的集团。因此,如果您在1页使用Bloc listener,然后在另一页再次调用该块,它将调用您在listener中设置的结果(在本例中显示snackBar)。
因此,只在需要使用该侦听器的页面上注册块。
示例:
从这里移除您的寄存器组