I'm trying to make a authentication screen with the BLoC pattern, but I have doubts about best practices even after reading the documentation of the flutter_bloc lib and reading multiple implementations.
The main problem I have is about state management. My authentication screen should handle the following states:
- Password visible or not.
- Show register or login screen.
- TextEdit validation.
- Loading (waiting for a Firebase response).
- if authenticated, show home. Else show the authentication page
I really wanted to do all the logic in blocs to make a clean architecture. Some people say they use a bloc per screen, sometime a bloc for the whole app, but flutter_bloc library says you should use a bloc for any widget complex enough.
My problem is, how can I deal with multiple states?
- If I store variables in states classes extended from the mother AuthState class, I can't access it in mapEventToState because the block receives the mother just the AuthState class.
- I tried handling all states in the same bloc by passing the current state in a event (as I will show in the code below), but then I can't properly set the initial state.
What's the best practice solution?
- Passing all state classes as variables in the mother AuthState class? Then I could persist data using "state.passwordFieldState". But I never saw something like that. I bet it's a wrong approach.
- Create a model to store the state and manipulate the model when a change event enter the bloc?
- Creating multiple blocs or cubits? One cubit for authentication, 1 cubit for password visibility, one bloc for authentication handling? My concern with that would be nesting bloc builders.
- Or should I forget about blocs for simple things and use providers instead? I wouldn't like to do that because it can lead to spaghetti code.
Here's my code:
class AuthState extends Equatable{
@override
List<Object> get props => [];
}
class PasswordFieldState extends AuthState{
final bool isObscured;
PasswordFieldState({this.isObscured});
@override
List<Object> get props => [isObscured];
}
class AuthEvent extends Equatable{
@override
List<Object> get props => [];
}
class SetObscurePassword extends AuthEvent{
bool isObscured = false;
}
class passwordTextEditChanged extends AuthEvent{}
class emailTextEditChanged extends AuthEvent{}
class AuthBloc extends Bloc<AuthEvent,AuthState> {
AuthBloc(AuthState initialState) : super(initialState);
@override
Stream<AuthState> mapEventToState(AuthEvent event) async* {
if (event is SetObscurePassword) {
yield PasswordFieldState(isObscured: !event.isObscured);
} else if (event is passwordTextEditChanged) {
print("validation handling");
} else if (event is emailTextEditChanged) {
print("validation handling");
}
}