I have to provide multiple blocs to application level.
final withAuth = BlocProvider<AuthenticationBloc>(
bloc: _authenticationBloc,
child: app,
);
return BlocProvider<NotificationBloc>(
bloc: _notificationBloc,
child: withAuth,
);
Are there any cleaner solutions?
For now no but I am open to ideas.
One thing to keep in mind though is you don’t need to create all blocs at the root level. I would advise creating the bloc at the closest common ancestor of all widgets that will need the bloc.
Also, nothing prevents you from injecting the bloc via the constructor especially if it’s only used by one widget.
Let me know if that helps and if you have ideas for how you’d like to improve this I would love to hear them.
Closing for now. Please feel free to reopen if you have any suggestions or additional thoughts.
My suggestion would be something similar to what rebloc does
void main() {
final store = Store<AppState>(
initialState: AppState([1, 2, 3]),
blocs: [
NumbersBloc(),
],
);
runApp(
StoreProvider<AppState>(
store: store,
child: HomeScreen(),
),
);
}
Notice in this example that you can pass multiple blocs to the store object because it contains the state and blocs.
@chimon2000 yeah I thought about that and was worried about how to handle the typing when you are retrieving a bloc later on. I looked at rebloc but don't see this being handled (can you please point me to where those blocs are retrieved later on?).
The problem I have is a Bloc
is retrieved by the Bloc's type so for example, BlocProvider<CounterBloc>
can later be identified because you can do BlocProvider.of<CounterBloc>(context)
and the corresponding bloc can efficiently be found. If we remove this, then I am unsure of how you would identify/retrieve a bloc. Thoughts?
For now, I think I'm going to close this and leave it as is because it is working as intended (one provider per bloc). It is called a BlocProvider
(singular) after all.
Please feel free to comment with any suggestions/feedback and I'd be happy to reopen this 👍
Here's a link to rebloc's implementation But I agree, why would you need multiple declared at top level? @endigo , did you know where was a way to request the type of bloc you were looking for in the BlocProvider.of()
function?
static T of<T extends Bloc<dynamic, dynamic>>(BuildContext context) {
BlocProvider<T> provider =
context.ancestorWidgetOfExactType(_typeOf<BlocProvider<T>>());
return provider.bloc;
}
@ThinkDigitalRepair My solution is working fine. I ask any recommendation for a cleaner solution.
@felangel, you could accept them in a list and nest them and return a top level composite bloc which would keep the provider functionality the same
@ThinkDigitalRepair can you please share a code snippet of what you're thinking? I'm not sure I understand what you mean by "top level composite bloc"
@felangel. I'm thinking two things. I'm really rusty on my recursive functions, but it would look something like this.
The first idea uses the stackBlocs
method below to recursively nest the blocs wrapped in BlocProviders. The second just holds a list of all the Blocs and when the of()
function is called, the provider locates the bloc in its list of Blocs based on the type specified and returns it.
The below code isn't tested whatsoever, but it's a strong proof of concept.
import 'package:flutter/material.dart';
import 'package:bloc/bloc.dart';
/// A Flutter widget which provides a bloc to its children via `BlocProvider.of(context)`.
/// It is used as a DI widget so that a single instance of a bloc can be provided
/// to multiple widgets within a subtree.
class BlocProvider<T extends Bloc<dynamic, dynamic>> extends StatelessWidget {
/// The Bloc which is to be made available throughout the subtree
final T bloc;
final List<T> blocs;
/// The Widget and its descendants which will have access to the Bloc.
final Widget child;
BlocProvider({
Key key,
this.bloc,
this.blocs,
@required this.child,
})
: assert(bloc !=null && (blocs != null && blocs.isNotEmpty && !blocs.contains(null))),
assert(child != null),
super(key: key);
@override
Widget build(BuildContext context) {
return stackBlocs(blocs, child);
}
BlocProvider<dynamic> stackBlocs(List<Bloc> blocStack, Widget child) {
print(blocStack);
if (blocStack.length == 1)
return BlocProvider(bloc:blocStack.first, child: child,);
else
return BlocProvider(bloc: blocStack.removeAt(0), child: stackBlocs(blocStack, child));
}
/// Method that allows widgets to access the bloc as long as their `BuildContext`
/// contains a `BlocProvider` instance.
static T of<T extends Bloc<dynamic, dynamic>>(BuildContext context) {
BlocProvider<T> provider =
context.ancestorWidgetOfExactType(_typeOf<BlocProvider<T>>());
T bloc = provider.blocs[provider.blocs.indexWhere((bloc) => bloc is T)];
if (bloc == null) {
throw FlutterError(
'BlocProvider.of() called with a context that does not contain a Bloc of type $T.\n'
'No $T ancestor could be found starting from the context that was passed '
'to BlocProvider.of(). This can happen '
'if the context you use comes from a widget above your Bloc.\n'
'The context used was:\n'
' $context'
);
}
return bloc;
}
static Type _typeOf<T>() => T;
}
@ThinkDigitalRepair thanks for the example but I'm concerned that
BlocProvider<T> provider =
context.ancestorWidgetOfExactType(_typeOf<BlocProvider<T>>());
implies that you'll have a list of blocs of the same type (ie multiple CounterBlocs maintained by a single BlocProvider). Correct me if I'm wrong but I don't see this as a valid use-case and I also don't see how you'd know which bloc to return.
T bloc = provider.blocs[provider.blocs.indexWhere((bloc) => bloc is T)];
would always return the first bloc because they should all be of type T.
I believe the original question was about being able to pass multiple different blocs to BlocProvider
but in that case we lose the ability to find ancestorOfExactType
unless we keep a single list of all Bloc
s.
Personally I don't think this use-case makes sense because the purpose of a BlocProvider
is to provide a bloc to a subtree. This change would violate that assumption by making a single BlocProvider
responsible for multiple blocs.
Let me know if you disagree or if I misunderstood anything.
Oh yes, you're right. If you go the route where where you're using the stackBlocs function, then
static T of<T extends Bloc<dynamic, dynamic>>(BuildContext context) {
BlocProvider<T> provider =
context.ancestorWidgetOfExactType(_typeOf<BlocProvider<T>>());
bloc = provider.bloc;
if (bloc == null) {
throw FlutterError(
'BlocProvider.of() called with a context that does not contain a Bloc of type $T.\n'
'No $T ancestor could be found starting from the context that was passed '
'to BlocProvider.of(). This can happen '
'if the context you use comes from a widget above your Bloc.\n'
'The context used was:\n'
' $context'
);
}
return bloc;
}
should suffice
@ThinkDigitalRepair I'll play around with it and see how it performs. Thanks again for the example 👍
If not, then the of function could take a Type
parameter and then find the bloc that is of that type.
Example:
void main() {
var list = [B(), C(), D()].lastWhere((obj)=> obj is D);
print(list);
}
abstract class A{}
class B extends A{}
class C extends A {}
class D extends C{}
You're welcome!
You can also use a named factory constructor to call that stackBlocs method so you don't have to make the default constructor complicated .
Any news about @ThinkDigitalRepair solution? I'm currently having the same problem as OP
As far as I know it’s not possible to do this without significant performance implications. What is the problem exactly? There’s nothing wrong with having multiple bloc providers.
The fact that it's not an optimal solution for people wanting the same level blocs. It's clunky to have 3 widgets nested right after each other to achieve a different effect. Performance is great, but people still choose Python over C when developing because they prefer ease
I'm in favor of having it as a second, lesser used option and let the user deal with the performance hit if they so choose. It beats someone else creating a separate package just for that singular widget.
Flutter is all about composition of widgets so I don’t really think it’s any different than other aspects of flutter. You can always create a statelesswidget wrapper around all the top level bloc providers
What do you mean?
On Fri, Feb 8, 2019, 11:58 AM Felix Angelov notifications@github.com
wrote:
Flutter is all about composition of widgets so I don’t really think it’s
any different than other aspects of flutter. You can always create a
statelesswidget wrapper around all the top level bloc providers—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/felangel/bloc/issues/15#issuecomment-461927816, or mute
the thread
https://github.com/notifications/unsubscribe-auth/AV-HfcjXwPVmCPGhbT_LbJNuIQNFR3OAks5vLdbrgaJpZM4Yd1a_
.
I mean you can always do something like:
class GlobalBlocs extends StatelessWidget {
final Widget child;
GlobalBlocs({Key key, this.child}) : super(key: key);
@override
Widget build(BuildContext context) {
return BlocProvider(
bloc: blocA,
child: BlocProvider(
bloc: blocB,
child: child,
),
);
}
}
And then use just GlobalBlocs
as a widget (but I still would not recommend this).
Also, I think it would be useful for you to read the official state management docs on flutter.io around using ScopedModel https://flutter.io/docs/development/data-and-backend/state-mgmt/simple
"The scoped_model package relies on types to find the right model, and the
If you want to provide more than one model, you need to nest the ScopedModels"
This is how BlocProvider
works as well so you can see the Flutter team has taken the exact same approach.
I would love to hear people's thoughts on #108 as a potential solution for this issue.
BlocProviderTree
addresses this and is available in flutter_bloc: 0.7.0
One thing to keep in mind though is you don’t need to create all blocs at the root level. I would advise creating the bloc at the closest common ancestor of all widgets that will need the bloc.
I have two different screen in my app, where I want to access the same bloc instance. And for that I think I will have to use BlocProvider at root level only or is there any way of using same bloc instance in different screens?
One way I can think of is to export the instance of Bloc from one file and use the same created instance across different files. But not sure if this would be a good solution??
Yes, that's how you're supposed to do it.
On Mon, Jul 8, 2019 at 12:13 AM Pavan Vora notifications@github.com wrote:
One thing to keep in mind though is you don’t need to create all blocs at
the root level. I would advise creating the bloc at the closest common
ancestor of all widgets that will need the bloc.I have two different screen in my app, where I want to access the same
bloc provider. And for that I think I will have to use BlocProvider at root
level only or is there any way of using same bloc instance in different
screens?I way I can think of is to export the instance of Bloc from one file and
use the same created instance across different files. But not sure if this
would be a good solution??—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/felangel/bloc/issues/15?email_source=notifications&email_token=AFPYO7IGMZYJA6OSSOPFVRLP6LSJFA5CNFSM4GDXK272YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGODZMF4EY#issuecomment-509107731,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AFPYO7K4AA2XYC4GC5ZQPE3P6LSJFANCNFSM4GDXK27Q
.>
Think Digital
323-638-9448
760-678-8833
Facebook.com/ThinkDigitalRepair
here I can see one more solution that is doing the same thing as providing all the bloc at one place. I was wondering which one will be a good to go with? Inserting all the BlocProviders in a list like given here OR to make a instance and export it from a file and use the same instance wherever required?
Because BlocProvider
is a Widget
you can't you should not reuse the same instance for an other part of your sub-tree.
But you can still create a reusable stateless Widget
to wrap a specific widget tree structure (including BlocProviders
) like here.
I'm not telling to make instance of BlocProvider. By making instance I mean instance of the bloc class which we do pass in BlocProvider's bloc argument.
@pavanvora You want to reuse bloc
instances to create multiple BlocProvider
anywhere in the subtree ?
Exactly because I need some BlocProvider in two different screens and I'm not sure if it would be good or efficient by performance to provide all the BlocProvider at the root level?
On my side I never had any problem by providing a bloc from the root level.
If you want to simply reuse the same bloc in a many the sub-tree that's how you should do with the BlocProvider
.
NB: You retrieve the Bloc
value of the BlocProvider
from the widget tree so maybe with a deep widget tree, but I never made a really deep widget tree but if there is a problem I guess it will also cause many flutter performance issue that are using the same strategy (MediaQuery, Themes, Localizations ...).
Ohhkay, So I can provide all my BlocProvider's
at the root level. Thanks very much @axellebot. I was wondering what are the disadvantage of reusing the same bloc
class instance across different screen by creating multiple BlocProvider
?
You should provide a bloc only in the sub-tree where you need to access it. But if you need it in two sub-tree it makes sense to provide the bloc from the common parent of both sub-tree (it can be the root of the tree). Np you can come on gitter if you need deeper help about bloc packages.
Most helpful comment
I mean you can always do something like:
And then use just
GlobalBlocs
as a widget (but I still would not recommend this).Also, I think it would be useful for you to read the official state management docs on flutter.io around using ScopedModel https://flutter.io/docs/development/data-and-backend/state-mgmt/simple
"The scoped_model package relies on types to find the right model, and the part makes it clear what type we’re providing here.
If you want to provide more than one model, you need to nest the ScopedModels"
This is how
BlocProvider
works as well so you can see the Flutter team has taken the exact same approach.