I'm trying to define a BaseMultiBlocProvider class which gives me more control to invoke bloc on widget init & rebuild and helps reduce boilerplate code. But doing this compiler keeps complaining about BlocProvider.of() called with a context that does not contain a Bloc of type ... down on the widget tree.
import 'package:flutter/widgets.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
class BaseMultiBlocView extends StatefulWidget {
const BaseMultiBlocView({
Key key,
@required this.items,
this.child,
}) : assert(items != null),
super(key: key);
final List<MultiBlocViewItem> items;
final Widget child;
@override
_BaseMultiBlocViewState createState() => _BaseMultiBlocViewState();
}
class _BaseMultiBlocViewState extends State<BaseMultiBlocView> {
@override
void initState() {
super.initState();
widget.items.map((item) {
if (item.onBlocReady != null && !item.isExisting) {
item.onBlocReady(item.bloc);
}
});
}
@override
void didUpdateWidget(BaseMultiBlocView oldWidget) {
super.didUpdateWidget(oldWidget);
widget.items.map((item) {
if (item.onRebuild != null) {
item.onRebuild(item.bloc);
}
});
}
@override
Widget build(BuildContext context) {
return MultiBlocProvider(
providers: widget.items
.map(
(item) => item.isExisting
? BlocProvider.value(
value: item.bloc,
)
: BlocProvider(
create: (_) => item.bloc,
),
)
.toList(growable: false),
child: widget.child,
);
}
}
class MultiBlocViewItem<T extends Bloc<dynamic, dynamic>> {
const MultiBlocViewItem({
@required this.bloc,
this.onBlocReady,
this.onRebuild,
this.isExisting = false,
}) : assert(bloc != null);
final bool isExisting;
final T bloc;
final void Function(T) onBlocReady;
final void Function(T) onRebuild;
}
Can you help me clarify what did I do wrong about the code?
Hi @dungnv2602 馃憢
Thanks for opening an issue!
The problem is you鈥檙e mapping a List
This is the same reason why MultiBlocProvider takes a List<BlocProvider> and not a List<Bloc>.
Can you describe why you need this widget and what problem you鈥檙e trying to solve? Thanks and hope that helps 馃憤
My problem is I want more fine control over when bloc invokes event. As you can see from my code above, what I'm trying to do is invoking bloc only in initState. Because if I don't do that, normally in situations which I want to invoke bloc on create, I will implement bloc and then use cascade like this.
MultiBlocProvider(
providers: [
BlocProvider(
create: (_) => TmdbBloc<MovieAccountStatus>(locator<TmdbRepo>())
..add( // cascade
BlocLoad(...),
),
),
),
BlocProvider(
create: (_) =>
TmdbBloc<List<UserListItemStatus>>(locator<TmdbRepo>())
..add( // cascade
BlocLoad(...),
),
),
],
),
I feel this approach is somewhat wrong as I scare whether or not it will reinvoke when widget rebuild or maybe this is not a good practice.
Can you help me clarify this?
@dungnv2602 create will only be called once so I would recommend using the cascade approach rather than the custom MultiBlocView.
I'm clear now, thank you so much @felangel.
Most helpful comment
I'm clear now, thank you so much @felangel.