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:
Widget tree as follows:
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?
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With