Flutter
BlocListener
Handle side effects with BlocListener.
What is BlocListener?
BlocListener is a widget that runs a side effect when a Bloc or Cubit state changes. Tasks like showing a snackbar, navigating, or opening a dialog are done with BlocListener instead of BlocBuilder. The listener callback is called once per state change.
BlocListener<LoginBloc, LoginState>(
listener: (context, state) {
if (state is LoginSuccess) {
Navigator.pushNamed(context, '/home');
}
},
child: Text('Login'),
)
listenWhen
The listenWhen callback conditions when the listener runs. For example, to run only on success you write listenWhen: (previous, current) => current is LoginSuccess. This prevents unnecessary side effects.
BlocListener<LoginBloc, LoginState>(
listenWhen: (prev, curr) => curr is LoginSuccess,
listener: (context, state) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Login success')));
},
child: Container(),
)
Exercise Listen to the state stream
bloc.stream.listen is the foundation of BlocListener. Create a LoginBloc, declare a String? message. Listen to the stream and when the state is LoginSuccess, assign 'Welcome ${state.user}' to message. Trigger the event, wait, and print message.
Show example solution
import 'package:bloc/bloc.dart';
abstract class LoginEvent {}
class LoginSubmittedEvent extends LoginEvent {}
abstract class LoginState {}
class LoginLoading extends LoginState {}
class LoginSuccess extends LoginState {
final String user;
LoginSuccess(this.user);
}
class LoginBloc extends Bloc<LoginEvent, LoginState> {
LoginBloc() : super(LoginLoading()) {
on<LoginSubmittedEvent>((event, emit) =>
emit(LoginSuccess('Ayşe')));
}
}
void main() async {
final bloc = LoginBloc();
String? message;
bloc.stream.listen((state) {
if (state is LoginSuccess) {
message = 'Welcome ${state.user}';
}
});
bloc.add(LoginSubmittedEvent());
await Future.delayed(Duration(milliseconds: 10));
print(message);
}
Test yourself
-
When is BlocListener used instead of BlocBuilder?
- To fetch data from the Bloc
- When the UI needs to be rebuilt
- Just to read the state
- When a side effect (navigation, snackbar) is needed
Show answer
When a side effect (navigation, snackbar) is needed — BlocBuilder rebuilds the UI; BlocListener performs side effects and does not produce a widget.
-
BlocListener parameter
BlocListener<LoginBloc, LoginState>(
____: (context, state) {
if (state is LoginSuccess) {
print('Giriş başarılı');
}
},
child: Container(),
)
Show answer
BlocListener<LoginBloc, LoginState>(
listener: (context, state) {
if (state is LoginSuccess) {
print('Giriş başarılı');
}
},
child: Container(),
)
-
BlocListener parts
- BlocListener
- Side effect widget
- listener
- Runs on state change
- listenWhen
- Condition to run
- child
- Child widget
Next lesson: Summary - Bloc advanced