Home > Back-end >  How to read states in widget from bloc?
How to read states in widget from bloc?

Time:05-06

How can I read the user auth states from my bloc? I am trying to use BlocBuilder, but not sure how do I get the data from AuthenticationState. I am trying to access the state and user. So the state should check for all the constructors, if authenticated then I want to display user data. Also in my app, I would like to automatically redirect an user to login page if he is not authorized - where this should be set up?

 child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            BlocBuilder<AuthenticationBloc, AuthenticationState>(builder: (context, state) {
              if(state is ...) {
                return Text("Unknown");
              }
            })
          ],
        ),
class AuthenticationState extends Equatable {
  final AuthStatus status;
  final User? user;

  const AuthenticationState._({this.user, this.status = AuthStatus.unknown});

  const AuthenticationState.unknown() : this._(status: AuthStatus.unknown);
  const AuthenticationState.authenticated({required User user})
      : this._(user: user, status: AuthStatus.authenticated);
  const AuthenticationState.unauthorized()
      : this._(status: AuthStatus.unauthenticated);

  @override
  List<Object?> get props => [user, status];
}
class AuthenticationBloc
    extends Bloc<AuthenticationEvent, AuthenticationState> {
  final AuthenticationRepository _authRepository;
  late StreamSubscription<AuthStatus> _authSubscription;

  AuthenticationBloc(
      {required AuthenticationRepository authenticationRepository})
      : _authRepository = authenticationRepository,
        super(const AuthenticationState.unknown()) {
    on<AuthStateChanged>(_onAuthStatusChanged);
    on<AuthenticationLogoutRequested>(_onLogoutRequested);
    _authSubscription = _authRepository.status
        .listen((status) => add(AuthStateChanged(authStatus: status)));
  }

  void _onAuthStatusChanged(
      AuthStateChanged event, Emitter<AuthenticationState> emit) {
    switch (event.authStatus) {
      case AuthStatus.unauthenticated:
        return emit(const AuthenticationState.unauthorized());
      case AuthStatus.authenticated:
        final User _user = User();
        return emit(AuthenticationState.authenticated(user: _user));
      default:
        return emit(AuthenticationState.unknown());
    }
  }

  void _onLogoutRequested(
      AuthenticationLogoutRequested event, Emitter<AuthenticationState> emit) {
    _authRepository.logOut();
  }
}

CodePudding user response:

If you are trying to check the state of user (authenticated or not) and show proper page according to its status i suggest to use get package. Get page middle ware is powerful and useful feature and you can call it in different situation.

Another solution for you is checking the user status in AuthenticationBloc.First save your user status in share it preference or hive or etc ... and everywhere you need to check user status, check it and by using bloc listener redirect your user to login page

CodePudding user response:

You access state variables simply with state.status inside the BlocBuilder. Here's an example of a BlocConsumer which is basically a BlocBuilder and BlocListener in the same widget.

 BlocConsumer<AuthenticationBloc, AuthenticationState>(
        listener: (context, state) {
          if (state.status == AuthStatus.unauthenticated) {
            // navigate back to login screen for example
          }
        },
        builder: (context, state) {
          switch (state.status) {
            case AuthStatus.unknown:
              // do what ya gotta do here
              break;
            case AuthStatus.unauthenticated:
              // do what ya gotta do here
              break;
            case AuthStatus.authenticated:
              return Text(state.user!.name); // example of showing user data
          }
        },
      ),

Your state class can also be simplified a bit. You don't need all those constructors. When you emit an updated AuthStatus that is a state update and will trigger the BlocConsumer. When the status is AuthStatus.authenticated you're also emitting the user with that state update.

class AuthenticationState extends Equatable {
  final AuthStatus status;
  final User? user;

  AuthenticationState(this.status)
      : user =
            null; // null on first app launch, updates when you emit a User on successful login

  @override
  List<Object?> get props => [status, user];
}

If you want the app to load in a logged in state you can check your _authRepository for a non null currentUser (assuming you're using FirebaseAuth it has a getter called currentUser and returns null if user isn't signed in) and if its not null you emit an AuthStatus.authenticated state with the user in the constructor of your bloc it it'll fire on app start.

  AuthenticationBloc(
      {required AuthenticationRepository authenticationRepository})
      : _authRepository = authenticationRepository,
        super(const AuthenticationState.unknown()) {
    on<AuthStateChanged>(_onAuthStatusChanged);
    on<AuthenticationLogoutRequested>(_onLogoutRequested);
    _authSubscription = _authRepository.status
        .listen((status) => add(AuthStateChanged(authStatus: status)));


// This is assuming your can access the user directly via _userRepository

  if(_userRepistory.user != null) {
      emit(AuthenticationState.authenticated(user: _userRepistory.user))
  }
  • Related