Your discomfort really has reason – no event should be fired from build()
method (build() could be fired as many times as Flutter framework needs)
Our case is to fire initial event on Bloc creation
Possibilities overview
- case with inserting Bloc with BlocProvider – this is preferred way
create:
callback is fired only once when BlocProvider is mounted & BlocProvider would close() bloc when BlocProvider is unmounted
class ExampleScreenState extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: BlocProvider(
create: (context) => ExampleBloc()..add(Fetch()), // <-- first event,
child: BlocBuilder<ExampleBloc, ExampleState>(
builder: (BuildContext context, state) {
...
},
),
),
);
}
}
- case when you create Bloc in
State
of Statefull widget
class _ExampleScreenStateState extends State<ExampleScreenState> {
ExampleBloc _exampleBloc;
@override
void initState() {
super.initState();
_exampleBloc = ExampleBloc();
_exampleBloc.add(Fetch());
// or use cascade notation
// _exampleBloc = ExampleBloc()..add(Fetch());
}
@override
void dispose() {
super.dispose();
_exampleBloc.close(); // do not forget to close, prefer use BlocProvider - it would handle it for you
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: BlocBuilder<ExampleBloc, ExampleState>(
bloc: _exampleBloc,
builder: (BuildContext context, state) {
...
},
),
);
}
}
- add first event on Bloc instance creation – this way has drawbacks when testing because first event is implicit
class ExampleBloc extends Bloc<ExampleEvent, ExampleState> {
...
ExampleBloc() {
add(Fetch());
}
}
// insert it to widget tree with BlocProvider or create in State
BlocProvider( create: (_) => ExampleBloc(), ...
// or in State
class _ExampleScreenStateState extends State<ExampleScreenState> {
final _exampleBloc = ExampleBloc();
...
PS feel free to reach me in comments