Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bloc widgets reftech data (rebuild) when navigating to another pageView or any View altogether

Context: I have an App that has a PageView to navigate between five screens using BottomNavigationBar, One page is making use of the Bloc Pattern (almost all of the pages will use Bloc in future releases) these Blocs are fetching data from backend service in filling the UI with the fetched data.

Problem: When navigating between pages at any level of the widget tree. the Bloc widget 'reset' and refetch the data from the repository.

As shown in the picture below:

Screenshot that shows the problem

Widget tree as follows:

  • main.dart
    • home.dart
      • timeline.dart (screen shown in the screenshot)

Tried-Solutions: I added the AutomaticKeepAliveClientMixin to the page class and to other pages but it didn't do the job.

Here is the code for the build method for the page shown in the above screenshot

   @override
  Widget build(BuildContext context) {

    super.build(context);

    return DefaultTabController(
      length: 4,
      child: Scaffold(
        backgroundColor: Colors.white,
        appBar: _builAppBarWithTabs(),
        body: Center(
          child: ConstrainedBox(
            constraints: BoxConstraints(maxWidth: 1200),
            child: ListView(
              scrollDirection: Axis.vertical,
              children: <Widget>[
                Padding(
                  padding: const EdgeInsets.only(bottom: 150),
                  child: Container(
                    height: 800,
                    child: CustomScrollView(
                      scrollDirection: Axis.vertical,
                      slivers: <Widget>[
                        SliverToBoxAdapter(
                          child: MasonryGrid(
                            column: getResponsiveColumnNumber(context, 1, 2, 6),
                            children: <Widget>[
                              // First Bloc
                              BlocProvider(
                                create: (context) {
                                  BrandBloc(repository: _brandRepository);
                                },
                                child: Container(
                                  width: 200,
                                  alignment: Alignment.center,
                                  height: 80,
                                  child: BrandScreen(
                                    brandBloc: context.bloc(),
                                  ),
                                ),
                              ),
                              CategoryScreen(
                                // Second Bloc
                                categoryBloc: CategoryBloc(
                                  repository: context.repository(),
                                ),
                              ),
                              Container(
                                width: 200,
                                alignment: Alignment.center,
                                height: 330,
                                child: _buildFeaturedItemsList(),
                              ),
                              Placeholder(
                                strokeWidth: 0,
                                color: Colors.white,
                              )
                            ],
                          ),
                        ),
                      ],
                    ),
                  ),
                ),


              ],
            ),
          ),
        ),
      ),
    );
  }

here is the code for class timeline.dart

here is the code for class home.dart that contains the BottomNavigationBar class

Question: How to stop the blocs from fetching the data each time the widget rebuilds?

like image 297
Waleed Alrashed Avatar asked Jun 08 '20 20:06

Waleed Alrashed


1 Answers

I finally got my head around the problem As it turned out, it was not about the bloc as much it was a problem related to PageView.

I wrapped the PageView with PageStorage widget as follows:

final PageStorageBucket bucket = PageStorageBucket(); //PageStorageBucket
  static List<Widget> pages = [
    Timeline(pageController: pageController, key: PageStorageKey('timeline')),
    Search(key: PageStorageKey('search')),
    LikeScreen(key: PageStorageKey('like')),
    CartScreen(key: PageStorageKey('cart')),
    storageService.getFromDisk('api_token') != null
        ? ProfileScreen(key: PageStorageKey('profile'))
        : AuthChooserScreen(key: PageStorageKey('auth')),
  ];
  @override
  Widget build(BuildContext context) {
    super.build(context);
    return SafeArea(
      top: true,
      bottom: true,
      child: Scaffold(
        backgroundColor: Colors.white,
        key: _scaffoldKey,
        //Wrapped  PageView with PageStorage
        body: PageStorage(
          bucket: bucket,
          child: PageView(
            children: pages,
            controller: pageController,
            onPageChanged: onPageChanged,
            physics: NeverScrollableScrollPhysics(),
          ),
        ),
        bottomNavigationBar: _buildBottomNavigationBar(),
      ),
    );
  }

Every page is assigned a PageStorageKey which is used to save and restore values that can outlive the widget

Thanks to this great medium article which explains it perfectly: Keeping State with the Bottom Navigation Bar in Flutter

like image 84
Waleed Alrashed Avatar answered Oct 10 '22 13:10

Waleed Alrashed