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),
);
}
}
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.
context.read<T>()
context.watch<T>()
context.select<T>()
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:
final selectedTab = context.select((HomeCubitClient cubit) => cubit.state.tab);
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 when clientId
varies inside new state.
you can achieve similar thing using BlocBuilder
and its buildWhen
method by nesting two of them which is tedious.