flutter_login 和 flutter_bloc 身份验证后导航:BlocListener 未监听状态更改
flutter_login and flutter_bloc navigation after authentication: BlocListener not listening to state change
我正在尝试结合文档中的 this with bloc, using this 设计模式。
状态实例化后,BlocListener 停止侦听身份验证集团,我有点被迫使用登录表单的 onSubmitAnimationCompleted 方法进行路由,这首先使侦听器无用。
MaterialApp() 与文档中提供的示例相同(我试图从登录屏幕(在本例中为 initialRoute)导航到主屏幕)
登录表单如下所示:
@override
Widget build(BuildContext context) {
return BlocListener<AuthenticationBloc, AuthenticationState> (
listener: (context, state) {
// first time around state is read
if (state is AuthenticationAuthenticated) {
Navigator.of(context).pushNamed(Home.routeName);
}
},
child: BlocBuilder(
bloc: _loginBloc,
builder: (BuildContext context, state) {
return FlutterLogin(
title: 'Login',
logo: const AssetImage('lib/assets/madrid.png'),
onLogin: _authUser,
onSignup: _signupUser,
onRecoverPassword: _recoverPassword,
loginProviders: <LoginProvider>[
... Providers here...
],
// if this method is omitted, I'll get a [ERROR:flutter/lib/ui/ui_dart_state.cc(209)]
onSubmitAnimationCompleted: () {
Navigator.of(context).pushNamed(Home.routeName);
},
);
},
),
);
}
- 我在两个块之间拆分事件和状态,'AuthenticationBloc'(包装整个应用程序,如果已存储令牌,则状态将为 'AuthenticationAuthenticated')和 'LoginBloc'(使用对于 login/logout 个事件)
#1 当我点击注册按钮时,关联的方法将调用 _loginBloc?.add(SignUpButtonPressed(email: email, password: password))
#2 快进到集团:
LoginBloc({required this.authenticationBloc, required this.loginRepository})
: super(const SignInInitial()) {
on<SignUpButtonPressed>(_signUp);
}
...
FutureOr<void> _signUp<LoginEvent>(SignUpButtonPressed event, Emitter<LoginState> emit) async {
emit(const SignInLoading());
try {
final credentials = User(email: event.email, password: event.password);
final success = await loginRepository.signUp(credentials);
if (success) {
final token = await loginRepository.signIn(credentials);
authenticationBloc.add(LoggedIn(email: event.email, token: token));
} else {
emit(const SignInFailure(error: 'Something went wrong'));
}
} on Exception {
emit(const SignInFailure(error: 'A network Exception was thrown'));
} catch (error) {
emit(SignInFailure(error: error.toString()));
}
}
- 这是成功的,它触发了身份验证块:
AuthenticationBloc({required this.userRepository})
: super(const AuthenticationUninitialized()) {
on<LoggedIn>(_loggedIn);
}
...
FutureOr<void> _loggedIn<AuthenticationEvent>(LoggedIn event, Emitter<AuthenticationState> emit) async {
await userRepository?.persistEmailAndToken(
event.email, event.token);
await _initStartup(emit);
}
...
Future<void> _initStartup(Emitter<AuthenticationState> emit) async {
final hasToken = await userRepository?.hasToken();
if (hasToken != null && hasToken == true) {
emit(const AuthenticationAuthenticated());
return;
} else {
emit(const AuthenticationUnauthenticated());
}
}
...最后,状态更新为 AuthenticationAuthenticated,这是预期的行为,观察者按预期记录转换。
现在,此状态更改应从 BlocListener 中触发导航,但不会。
我想去掉 onSubmitAnimationCompleted 里面的 Navigator,依赖状态变化。
我认为这可能是由 Equatable 引起的,因为我的州对此进行了扩展:
abstract class AuthenticationState extends Equatable {
const AuthenticationState();
@override
List<Object> get props => [];
}
class AuthenticationAuthenticated extends AuthenticationState {
const AuthenticationAuthenticated();
}
但是,我已经尝试了几个小时,但我在文档中找不到任何东西,github,或者说是有效的。
因此,我无法摆脱 onSubmitAnimationCompleted 中的 Navigator(我猜 BlocListener 在提交表单时被处理掉,并且在动画完成之前),但在这个过程中我已经成功了为了使我的状态管理干净而健壮,所以我将在下面留下一个小备忘单,请随时发表评论或发表您的意见:
- 假设您的小部件的构建方法如下所示:
@override
Widget build(BuildContext context) {
return BlocListener<AuthenticationBloc, AuthenticationState> (
bloc: _authenticationBloc,
listener: (context, state) {
if (state.status == AuthenticationAppState.authenticated) {
Navigator.of(context).pushNamed(Home.routeName);
}
},
child: BlocBuilder(
bloc: _loginBloc,
builder: (BuildContext context, state) {
return FlutterLogin(
...
- 并且您的活动扩展了 Equatable
import 'package:equatable/equatable.dart';
abstract class AuthenticationEvent extends Equatable {
const AuthenticationEvent();
@override
List<Object> get props => [];
}
class LoggedIn extends AuthenticationEvent {
final String email;
final dynamic token;
const LoggedIn({ required this.email, this.token });
@override
List<Object> get props => [email, token];
}
- 您的 Bloc 将如下所示:
class AuthenticationBloc extends Bloc<AuthenticationEvent, AuthenticationState> {
final SecureStorage? userRepository;
AuthenticationBloc({required this.userRepository})
: super(const AuthenticationState.uninitialized()) {
on<LoggedIn>(_loggedIn);
on<LoggedOut>(_loggedOut);
on<UserDeleted>(_userDeleted);
}
...
FutureOr<void> _loggedOut<AuthenticationEvent>(LoggedOut event, Emitter<AuthenticationState> emit) async {
emit(const AuthenticationState.loggingOut());
await userRepository?.deleteToken();
// API calls here
// event has access the event's properties e.g. event.email etc
}
- 状态已重构为:
import 'package:equatable/equatable.dart';
enum AuthenticationAppState {
uninitialized,
unauthenticated,
authenticated,
loggingOut,
loading,
}
class AuthenticationState extends Equatable {
const AuthenticationState._({
required this.status,
});
const AuthenticationState.uninitialized() : this._(status: AuthenticationAppState.uninitialized);
const AuthenticationState.unauthenticated() : this._(status: AuthenticationAppState.unauthenticated);
const AuthenticationState.authenticated() : this._(status: AuthenticationAppState.authenticated);
const AuthenticationState.loggingOut() : this._(status: AuthenticationAppState.loggingOut);
const AuthenticationState.loading() : this._(status: AuthenticationAppState.loading);
final AuthenticationAppState status;
@override
List<Object> get props => [status];
}
我正在尝试结合文档中的 this with bloc, using this 设计模式。
状态实例化后,BlocListener 停止侦听身份验证集团,我有点被迫使用登录表单的 onSubmitAnimationCompleted 方法进行路由,这首先使侦听器无用。
MaterialApp() 与文档中提供的示例相同(我试图从登录屏幕(在本例中为 initialRoute)导航到主屏幕)
登录表单如下所示:
@override
Widget build(BuildContext context) {
return BlocListener<AuthenticationBloc, AuthenticationState> (
listener: (context, state) {
// first time around state is read
if (state is AuthenticationAuthenticated) {
Navigator.of(context).pushNamed(Home.routeName);
}
},
child: BlocBuilder(
bloc: _loginBloc,
builder: (BuildContext context, state) {
return FlutterLogin(
title: 'Login',
logo: const AssetImage('lib/assets/madrid.png'),
onLogin: _authUser,
onSignup: _signupUser,
onRecoverPassword: _recoverPassword,
loginProviders: <LoginProvider>[
... Providers here...
],
// if this method is omitted, I'll get a [ERROR:flutter/lib/ui/ui_dart_state.cc(209)]
onSubmitAnimationCompleted: () {
Navigator.of(context).pushNamed(Home.routeName);
},
);
},
),
);
}
- 我在两个块之间拆分事件和状态,'AuthenticationBloc'(包装整个应用程序,如果已存储令牌,则状态将为 'AuthenticationAuthenticated')和 'LoginBloc'(使用对于 login/logout 个事件)
#1 当我点击注册按钮时,关联的方法将调用 _loginBloc?.add(SignUpButtonPressed(email: email, password: password))
#2 快进到集团:
LoginBloc({required this.authenticationBloc, required this.loginRepository})
: super(const SignInInitial()) {
on<SignUpButtonPressed>(_signUp);
}
...
FutureOr<void> _signUp<LoginEvent>(SignUpButtonPressed event, Emitter<LoginState> emit) async {
emit(const SignInLoading());
try {
final credentials = User(email: event.email, password: event.password);
final success = await loginRepository.signUp(credentials);
if (success) {
final token = await loginRepository.signIn(credentials);
authenticationBloc.add(LoggedIn(email: event.email, token: token));
} else {
emit(const SignInFailure(error: 'Something went wrong'));
}
} on Exception {
emit(const SignInFailure(error: 'A network Exception was thrown'));
} catch (error) {
emit(SignInFailure(error: error.toString()));
}
}
- 这是成功的,它触发了身份验证块:
AuthenticationBloc({required this.userRepository})
: super(const AuthenticationUninitialized()) {
on<LoggedIn>(_loggedIn);
}
...
FutureOr<void> _loggedIn<AuthenticationEvent>(LoggedIn event, Emitter<AuthenticationState> emit) async {
await userRepository?.persistEmailAndToken(
event.email, event.token);
await _initStartup(emit);
}
...
Future<void> _initStartup(Emitter<AuthenticationState> emit) async {
final hasToken = await userRepository?.hasToken();
if (hasToken != null && hasToken == true) {
emit(const AuthenticationAuthenticated());
return;
} else {
emit(const AuthenticationUnauthenticated());
}
}
...最后,状态更新为 AuthenticationAuthenticated,这是预期的行为,观察者按预期记录转换。
现在,此状态更改应从 BlocListener 中触发导航,但不会。
我想去掉 onSubmitAnimationCompleted 里面的 Navigator,依赖状态变化。
我认为这可能是由 Equatable 引起的,因为我的州对此进行了扩展:
abstract class AuthenticationState extends Equatable {
const AuthenticationState();
@override
List<Object> get props => [];
}
class AuthenticationAuthenticated extends AuthenticationState {
const AuthenticationAuthenticated();
}
但是,我已经尝试了几个小时,但我在文档中找不到任何东西,github,或者说是有效的。
因此,我无法摆脱 onSubmitAnimationCompleted 中的 Navigator(我猜 BlocListener 在提交表单时被处理掉,并且在动画完成之前),但在这个过程中我已经成功了为了使我的状态管理干净而健壮,所以我将在下面留下一个小备忘单,请随时发表评论或发表您的意见:
- 假设您的小部件的构建方法如下所示:
@override
Widget build(BuildContext context) {
return BlocListener<AuthenticationBloc, AuthenticationState> (
bloc: _authenticationBloc,
listener: (context, state) {
if (state.status == AuthenticationAppState.authenticated) {
Navigator.of(context).pushNamed(Home.routeName);
}
},
child: BlocBuilder(
bloc: _loginBloc,
builder: (BuildContext context, state) {
return FlutterLogin(
...
- 并且您的活动扩展了 Equatable
import 'package:equatable/equatable.dart';
abstract class AuthenticationEvent extends Equatable {
const AuthenticationEvent();
@override
List<Object> get props => [];
}
class LoggedIn extends AuthenticationEvent {
final String email;
final dynamic token;
const LoggedIn({ required this.email, this.token });
@override
List<Object> get props => [email, token];
}
- 您的 Bloc 将如下所示:
class AuthenticationBloc extends Bloc<AuthenticationEvent, AuthenticationState> {
final SecureStorage? userRepository;
AuthenticationBloc({required this.userRepository})
: super(const AuthenticationState.uninitialized()) {
on<LoggedIn>(_loggedIn);
on<LoggedOut>(_loggedOut);
on<UserDeleted>(_userDeleted);
}
...
FutureOr<void> _loggedOut<AuthenticationEvent>(LoggedOut event, Emitter<AuthenticationState> emit) async {
emit(const AuthenticationState.loggingOut());
await userRepository?.deleteToken();
// API calls here
// event has access the event's properties e.g. event.email etc
}
- 状态已重构为:
import 'package:equatable/equatable.dart';
enum AuthenticationAppState {
uninitialized,
unauthenticated,
authenticated,
loggingOut,
loading,
}
class AuthenticationState extends Equatable {
const AuthenticationState._({
required this.status,
});
const AuthenticationState.uninitialized() : this._(status: AuthenticationAppState.uninitialized);
const AuthenticationState.unauthenticated() : this._(status: AuthenticationAppState.unauthenticated);
const AuthenticationState.authenticated() : this._(status: AuthenticationAppState.authenticated);
const AuthenticationState.loggingOut() : this._(status: AuthenticationAppState.loggingOut);
const AuthenticationState.loading() : this._(status: AuthenticationAppState.loading);
final AuthenticationAppState status;
@override
List<Object> get props => [status];
}