Reputation: 377
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
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