Flutter build called multiple times

5,934

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.

Share:
5,934
loki
Author by

loki

Updated on December 11, 2022

Comments

  • loki
    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
    loki over 3 years
    With this. initState is called twice.
  • Taha Malik
    Taha Malik over 3 years
    No it will not.
  • Taha Malik
    Taha Malik over 3 years
    If it solved your issue, please accept my answer then.