On my apps home page, I have a list view that rebuilds whenever the user clicks on a new page. I have implemented the block pattern using the flutter_bloc plugin but I don't know how to change the state from another widget.
On my apps home page, I have a list view that rebuilds whenever the user clicks on a new page. I have implemented the block pattern using the flutter_bloc plugin but I don't know how to change the state from another widget.
Two things you will have to keep in mind for changing state with flutter bloc:
Case 1. You need to provide bloc to widget subtree within one route.
To provide a single instance of a bloc to multiple widgets within a subtree you use BlocProvider widget. It creates bloc instance, automatically disposes of it when needed and provides bloc to its children via BlocProvider.of<T>(context), where T is the name of your bloc:
BlocProvider(
create: (BuildContext context) => BlocA(),
child: ChildA(),
);
Keep in mind, that by deafult it is created with property lazy: true, means that create: (BuildContext context) => BlocA(), will be executed after invoke of BlocProvider.of<T>(context). If you dont want it - set lazy: false in advance.
Case 2. You need to provide bloc to widgets from another route (to another context).
BlocProvider automatically disposes of a bloc instance with context of new route instantiated, but that will not happen if you use BlocProvider.value:
BlocProvider.value(
value: BlocProvider.of<BlocA>(context),
child: ScreenA(),
);
Important note: BlocProvider.value should only be used for providing existing instances to new subtree, do not create Bloc instance with it
Starting from bloc v6.1.0 context.bloc and context.repository are deprecated in favor of context.read and context.watch.
context.select allows to update UI based on a part of a bloc state:
final name = context.select((UserBloc bloc) => bloc.state.user.name);
context.read access a bloc with a BuildContext and do not result rebuilds.
context.watch gets a value from the nearest ancestor provider of its type and subscribes to the provider.
To access the bloc's state
If you need a widget rebuilding due bloc value changing use context.watch or BlocBuilder:
// Using context.watch at the root of the build method will result in the entire widget being rebuilt when the bloc state changes.
@override
Widget build(BuildContext context) {
final state = context.watch<MyBloc>().state;
return Text('$state');
}
or with BlocBuilder:
// If the entire widget does not need to be rebuilt, either use BlocBuilder to wrap the parts that should rebuild
@override
Widget build(BuildContext context) {
return BlocBuilder<MyBloc, MyState>(
builder: (context, state) => Text('$state'),
);
}
To access the bloc so that an event can be added
Use context.read:
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: () => context.read<MyBloc>().add(MyEvent()),
...
)
}
You can place the BlocProvider to a common ansestor like as a parent of your MaterialApp widget, or you can pass the bloc to your new page like this:
BlocProvider.value(
value: BlocProvider.of<BlocA>(context),
child: ScreenB(),
);