Reputation: 394
I'm working on a login screen for my app and I'm using a riverpod provider for the user auth state:
// Auth state union class
@freezed
class AuthState with _$AuthState {
const factory AuthState.initial() = _Initial;
const factory AuthState.loading() = _Loading;
const factory AuthState.unauthenticated({required String message}) = _UnAuthentication;
const factory AuthState.authenticated({required User user}) = _Authenticated;
}
// Auth state provider:
@Riverpod(keepAlive: true)
class AuthStateNotifer extends _$AuthStateNotifer {
@override
AuthState build() {
return const AuthState.initial();
}
Future<void> login({required String email, required String password}) async {
state = const AuthState.loading();
final response = await ref.watch(authServiceProvider).login(email: email, password: password);
state = response.fold(
(error) => AuthState.unauthenticated(message: error),
(user) => AuthState.authenticated(user: user),
);
}
Future<void> signup(RegistrationData registrationData) async {
state = const AuthState.loading();
final response = await ref.watch(authServiceProvider).signup(registrationData);
state = response.fold(
(error) => AuthState.unauthenticated(message: error),
(user) => AuthState.authenticated(user: user),
);
}
void checkIfLoggedIn() {
final response = ref.watch(authServiceProvider).checkIfLoggedIn();
state = response.fold(
() => const AuthState.unauthenticated(message: "User not logged in"),
(user) => AuthState.authenticated(user: user),
);
}
Future<void> signout() async {
await ref.watch(authServiceProvider).signout();
Future.delayed(const Duration(milliseconds: 500), () {
ref.invalidateSelf();
});
}
}
Inside my login page I have a listener that listens for the auth state change and is supposed to go to home page when user is logged in.
@override
Widget build(BuildContext context) {
ref.listen(
authStateNotiferProvider,
(previous, next) {
next.maybeWhen(
orElse: () => null,
authenticated: (user) =>
Navigator.of(context).pushReplacementNamed(HomePage.route),
unauthenticated: (message) {
showError(message);
},
);
},
);
///...
Unfortunately, this makes it so navigator gets called on every widget rebuild making it keep pushing the home page forever. How do I resolve this?
Upvotes: 0
Views: 830
Reputation: 21
issueis due to the fact that you're calling Navigator.of(context).pushReplacementNamed(HomePage.route) inside the build the correct code:
class YourLoginPage extends ConsumerWidget {
@override
Widget build(BuildContext context, ScopedReader watch) {
final authState = watch(authStateNotiferProvider);
// Use a flag to track whether navigation has already occurred
bool hasNavigated = false;
// Listen for auth state changes
authState.maybeWhen(
orElse: () {},
authenticated: (user) {
// Check if navigation has already occurred
if (!hasNavigated) {
// Navigate to the home page
Navigator.of(context).pushReplacementNamed(HomePage.route);
hasNavigated = true; // Set the flag to true
}
},
unauthenticated: (message) {
showError(message);
},
);
// Your widget build logic
return YourLoginPageWidget();
}
}
Amine K
Upvotes: 1