Reputation: 1556
I am using Bloc for my application, however I was doing something wrong and that is, providing all BlocProvider creates in the MaterialApp
and I would not like to follow that bad practice.
Let's suppose that when I navigate to ScreenA, we create the Bloc as follows :
case PageNames.screenA:
return PageTransition( // Some class that navigates
duration: const Duration(milliseconds: 400),
child: BlocProvider<ScreenABloc>(
create: (context) => ScreenABloc(),
child: const ScreenAPage(),
),
);
Now inside ScreenA, I will do a navigation to ScreenB, and everything is fine, however inside ScreenB at the bottom of my widget tree I want to access the ScreenABloc again, but I can't assign a BlocProvider.value
because I get :
ProviderNotFoundException (Error: Could not find the correct Provider<ScreenABloc> above this Welcome Widget
return BlocProvider.value(
value: BlocProvider.of<ScreenABloc>(context),
child: child ...
);
So I am not sure how to get the supplier that has already been created, or if I should re-create it or what to do in those cases.
Upvotes: 4
Views: 3731
Reputation: 24980
Using all BlocProviders
in the starting of the file is not always considered bad practice. as according to official docs
By default,
BlocProvider
will create the bloclazily
, meaning create will get executed when the bloc is looked up via BlocProvider.of(context).
So now, What are the use cases to use providers
globally?
When you want to access the providers almost everywhere in the app.
When to use providers
passing through routes ?
When only some screens needs access to the
bloc
you can pass value usingBlocProvider.value
According to the official docs of BlocProvider
in flutter_bloc
,follow these steps to pass BlocProvider
to the child screen.
BlocA()
BlocProvider(
lazy: false,
create: (BuildContext context) => BlocA(),
child: ChildA(),
);
BlocA
to ScreenA()
Make sure this is called from inside the ChildA()
BlocProvider.value(
value: BlocProvider.of<BlocA>(context),
child: ScreenA(),
);
ChildA
or ScreenA
retrieve value as:// with extensions
context.read<BlocA>();
// without extensions
BlocProvider.of<BlocA>(context);
Upvotes: 3
Reputation: 643
you should use BlocProvider.value
when you push a new route:
/// declare the bloc
final _screenABloc = ScreenABloc();
then use it in both ScreenA
and ScreenB
case PageNames.screenA:
return PageTransition( // Some class that navigates
duration: const Duration(milliseconds: 400),
child: BlocProvider.value(
value: _screenABloc,
child: const ScreenAPage(),
),
);
case PageNames.screenB:
return PageTransition( // Some class that navigates
duration: const Duration(milliseconds: 400),
child: BlocProvider.value(
value: _screenABloc,
child: const ScreenBPage(),
),
);
Upvotes: 1
Reputation: 1238
You can create a method of creating BlocProvider
in the screen itself, then you can use that method for navigating and creating providers for you.
Here's an example:
class MyWidget extends StatelessWidget {
const MyWidget({super.key});
static Widget create() {
return MultiBlocProvider(
providers: [
BlocProvider<SignInBloc>(
create: (BuildContext context) => SignInBloc(),
),
],
child: const SignInScreen(),
);
}
@override
Widget build(BuildContext context) {
return Container();
}
}
Upvotes: 1