Flutter build called multiple times
Solution 1
The best way is to add event in initState of you main route (Route that contains Bottom Navigation). As shown in below code.
class _MainPageState extends State<MainPage> {
int _index = 0;
@override
void initState() {
super.initState();
getIt<ListBloc>().add(const ListEvent.load(limit: 10));
}
@override
Widget build(BuildContext context) {
final List<Widget> _widgets = [
const ListPage(),
Scaffold(),
Scaffold(),
];
return Scaffold(
body: IndexedStack(
index: _index,
children: _widgets,
),
bottomNavigationBar: BottomNavigationBar(
...
class ListPage extends StatelessWidget {
const ListPage({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (_) =>
getIt<ListBloc>(),
child: SafeArea(
child: Scaffold(
appBar: AppBar(),
body: const List(),
),
),
);
}
}
Solution 2
I think the problem is in MainPage
. When you change selected page in bottom navigation bar you forces the call of build
of MainPage
but it recreates _widgets
variable every time and this forces update child widgets. Move final _widgets = ...
in class scope, i.e. your variable will be created once.
Also you should provide
Bloc on level above your bottom navigation bar item i.e. wrap ListPage
with BlocProvider
. And than it will be found in tree. Or try to use Builder
between BlocProvider
and SafeArea
in ListPage
.
To get ListBloc
you need to use BlocProvider.of<ListBloc>(context)
in a widget where you need bloc.
Solution 3
you can use StatefulWidget class with KeepAlive, according to official doc (Mark a child as needing to stay alive even when it's in a lazy list that would otherwise remove it).
In code :
class YourStatefulWidget extends StatefulWidget {
//add with AutomaticKeepAliveClientMixin to the state class
class _YourStatefulWidgetState extends State<YourStatefulWidget > with AutomaticKeepAliveClientMixin {
//add super.build(context) under the build method
Widget build(BuildContext context) {
super.build(context);
return //your widget
@override
bool get wantKeepAlive => true;
}
}
}
Or you can fixed logically by using a Boolean value form your state management class as the value wouldn't change if the widget get rebuild.
loki
Updated on December 11, 2022Comments
-
loki over 1 year
I have a bottom nav bar that has a list page that uses a bloc for the state.
class _MainPageState extends State<MainPage> { int _index = 0; @override Widget build(BuildContext context) { final List<Widget> _widgets = [ const ListPage(), Scaffold(), Scaffold(), ]; return Scaffold( body: IndexedStack( index: _index, children: _widgets, ), bottomNavigationBar: BottomNavigationBar( ... class ListPage extends StatelessWidget { const ListPage({Key key}) : super(key: key); @override Widget build(BuildContext context) { return BlocProvider( create: (_) => getIt<ListBloc>()..add(const ListEvent.load(limit: 10)), child: SafeArea( child: Scaffold( appBar: AppBar(), body: const List(), ), ), ); } }
The problem is
build
is beeing called 4 times. This causes the event fetching the list 4 times.Don't know where to add the event to prevent re-builds.
If I add the event in statefull widget's
initState
. Bloc does not recognize ListBloc beeing in the context when fetching the bloc down the widget tree. -
loki over 3 yearsWith this.
initState
is called twice. -
Taha Malik over 3 yearsNo it will not.
-
Taha Malik over 3 yearsIf it solved your issue, please accept my answer then.