Nishuthan S
Nishuthan S

Reputation: 1735

Flutter Bloc change state from different 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.

Upvotes: 3

Views: 13801

Answers (2)

Simon Sot
Simon Sot

Reputation: 3136

Two things you will have to keep in mind for changing state with flutter bloc:

  • Dependency injection (DI) of a bloc.
  • Interaction with your bloc instance.

Dependency injection of a 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

Interaction with your bloc instance

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()),
    ...
  )
}

Upvotes: 14

dshukertjr
dshukertjr

Reputation: 18612

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(),
);

Upvotes: 0

Related Questions