I am continuing a Flutter project of mine after quite some time and I no longer understand why a very basic pattern works.
As far as I remember and what I understand from the documentation, I need a BlocBuilder
to update a screen upon a state change. However, my app also updates the screen without a BlocBuilder
upon calling a Cubit
function. So when I click on a navigation tab, the other page in the stack appears on front.
Why is this, even though I am only working with StateLessWidget
s and no BlocBuilder
?
class HomePageClient extends StatelessWidget {
const HomePageClient({super.key});
@override
Widget build(BuildContext context) {
return BlocProvider<HomeCubitClient>(
create: (_) => HomeCubitClient(),
child: HomeViewClient(nextJobsBloc: nextJobsBloc,
specialTasksBloc: specialTasksBloc),);
}
}
class HomeViewClient extends StatelessWidget {
String? clientId;
@override
Widget build(BuildContext context) {
final selectedTab = context.select((HomeCubitClient cubit) => cubit.state.tab);
clientId = context.select((AppBloc bloc) => bloc.state.client!.clientId);
return Scaffold(
body: IndexedStack(
index: selectedTab.index,
children: [
HomeMainClient(),
PropertyListPage(clientId: clientId),
],
),
bottomNavigationBar: BottomAppBar(
shape: const CircularNotchedRectangle(),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
_HomeTabButton(
groupValue: selectedTab,
value: HomeTabClient.home,
label: 'HOME',
),
_HomeTabButton(
groupValue: selectedTab,
value: HomeTabClient.properties,
label: 'PROPERTIES',
),
],
),
),
);
}
}
class _HomeTabButton extends StatelessWidget {
const _HomeTabButton({
required this.groupValue,
required this.value,
required this.label,
});
final HomeTabClient groupValue;
final HomeTabClient value;
final String label;
@override
Widget build(BuildContext context) {
return TextButton(
style: TextButton.styleFrom(
foregroundColor: groupValue != value
? Colors.black
: Theme.of(context).colorScheme.secondary,
),
onPressed: () => context.read<HomeCubitClient>().setTab(value),
child: Text(label),
);
}
}
2
Answers
BlocBuilder we know its purpose is to rebuild the widget when the state changes.
After the Release of Bloc version 6.1.0. We got the access for three different methods.
Now obviously you can rebuild a widget using
BlocConsumer,BlocBuilder
but let’s say you need to subscribe to many blocs so there came a need for more granular approach like used in your bloc.
Simply In your case:
Is the one responsible for the rebuild of the widget.
context.select
here basically looks for the HomeCubitClient and subscribes to its state. It rebuilds only when the tab variable is changed. The line bellow it subscribes to another bloc and your widget will rebuild whenclientId
varies inside new state.you can achieve similar thing using
BlocBuilder
and itsbuildWhen
method by nesting two of them which is tedious.In this line in build method of
HomeViewClient
you are listening forHomeCubitClient
state updates. So ifHomeCubitClient
is changed then you active tab is changing correspondinglyIf you check the code of
BlocBuilder
and its parentBlocBuilderBase
you will see that it’s doing literally the same thing (but also overridesdidUpdateWidget
anddidChangeDependencies
). So it’s recommended to useBlocBuilder
in your case