Lyle Phillips
Lyle Phillips

Reputation: 377

Flutter Bloc - mapEventToState executes only once

Good day guys,

I am new to flutter. I'm trying simple state management using Bloc. I have a home screen which show/hides some widgets depending on the state. On a separate screen I have two buttons that add events to the stream which updates the state and then the widgets on the home screen react to the state updates. Its working fine but the UI only re-builds after the first event and on subsequent events the bloc yields the state but the UI does not update. Also in main.dart Material App is wrapped with MultBlocProvider. I'm from South Africa so I might not be able to immediately reply bc of timezones but any help will be hugely appreciated. Below are the code snippets.

auth_state.dart

class AuthState {
  bool isLoggedIn = false;
}

auth_event.dart

enum EventType { login, logout }

class AuthEvent {
  late EventType eventType;

  AuthEvent.login() {
    this.eventType = EventType.login;
  }

  AuthEvent.logout() {
    this.eventType = EventType.logout;
  }
}

auth_bloc.dart

class AuthBloc extends Bloc<AuthEvent, AuthState> {
  AuthBloc(AuthState initialState) : super(initialState);

  @override
  Stream<AuthState> mapEventToState(AuthEvent event) async* {
    switch (event.eventType) {
      case EventType.login:
        AuthState newState = state;
        newState.isLoggedIn = true;
        yield newState;
        break;
      case EventType.logout:
        AuthState newState = state;
        newState.isLoggedIn = false;
        yield newState;
        break;
      default:
        throw Exception('Event not found $event');
    }
  }
}

home_page.dart (snippet) -> bloc comsumer

 Padding(
   padding: const EdgeInsets.only(right: 30),
   child: BlocConsumer<AuthBloc, AuthState>(
     listener: (context, state) {},
     builder: (context, state) {
       return Visibility(
         visible: state.isLoggedIn,
         child: IconButton(
           key: HomePage.navigateToNotifications,
           onPressed: () {
             Navigator.push(
               context,
               MaterialPageRoute(
                 builder: (context) => Notifications()),
             );
           },
           icon: Icon(Icons.circle_notifications,
             size: 50, color: HexColor('27B88D'))),
       );
     }))

test_page.dart (snippet) -> fire bloc events

          ElevatedButton(
              onPressed: () =>
                  BlocProvider.of<AuthBloc>(context).add(AuthEvent.login()),
              child: Text('Log User in')),
          ElevatedButton(
              onPressed: () =>
                  BlocProvider.of<AuthBloc>(context).add(AuthEvent.logout()),
              child: Text('Log User out'))

Upvotes: 1

Views: 836

Answers (1)

Loren.A
Loren.A

Reputation: 5595

I find its easier just to declare separate state classes for states rather than new instances of the same state.

abstract class AuthState {}

class NotLoggedIn extends AuthState {}

class LoggedIn extends AuthState {}

Then your mapEventToState looks like this

  @override
  Stream<AuthState> mapEventToState(AuthEvent event) async* {
    switch (event.eventType) {
      case EventType.login:
        {
          yield LoggedIn();
          break;
        }

      case EventType.logout:
        {
          yield NotLoggedIn();
          break;
        }

      default:
        throw Exception('Event not found $event');
    }
  }

Then your BlocConsumer looks like this and it rebuilds as you expect

            Padding(
              padding: const EdgeInsets.only(right: 30),
              child: BlocConsumer<AuthBloc, AuthState>(
                listener: (context, state) {},
                builder: (context, state) {
                  return Visibility(
                    visible: state is LoggedIn ? true : false,
                    child: IconButton(
                        onPressed: () {},
                        icon: Icon(Icons.circle_notifications,
                            size: 50, color: Colors.amber)),
                  );
                },
              ),
            )

Upvotes: 1

Related Questions