I have a quite complex app structure and im wondering how to handle calling my events the right way. Imagine my widget tree. On top of everything I have the following file AppWrapper
with this
1. level file AppWrapper
...
return BlocProvider(
create: (context) => EventsBloc(
RepositoryProvider.of<EventRepository>(context),
RepositoryProvider.of<SocketRepository>(context),
)..add(LoadEventsEvent()),
...
child: RootScreen()
...
It calls LoadEventsEvent()
perfectly fine. Now in my RootScreen()
im trying to load a the event again.
2. level file RootScreen
...
BlocBuilder<DifferentBloc, DifferentBlocState>(
builder: (context, state) {
if (state.navbarItem == FMNavigation.home) {
// How to load LoadEventsEvent() here the right way??
return BlocProvider(
create: (context) => EventsBloc(
RepositoryProvider.of<EventRepository>(context),
RepositoryProvider.of<SocketRepository>(context),
)..add(LoadEventsEvent()),
child: HomeScreen(),
} else if (state.navbarItem == FMNavigation.chat) {
...
Now the above code works fine, its loading LoadEventsEvent()
like im expecting, but im using BlocProvider
for EventsBloc
two times now. From the docs it says:
Takes a Create function that is responsible for creating the Bloc or Cubit and a child which will have access to the instance via BlocProvider.of(context). It is used as a dependency injection (DI) widget so that a single instance of a Bloc or Cubit can be provided to multiple widgets within a subtree.
It seems like it's not meant to be used multiple times for the same bloc even if it works in my special case. No my second idea was to refactor this code to:
...
BlocBuilder<NavigationCubit, NavigationState>(
builder: (context, state) {
if (state.navbarItem == FMNavigation.home) {
context.read<EventsBloc>().add(LoadEventsEvent());
return HomeScreen();
} else if (state.navbarItem == FMNavigation.chat) {
...
But reading about context.read()
the docs say:
It will not make widget rebuild when the value changes and cannot be called inside [StatelessWidget.build]/[State.build]. On the other hand, it can be freely called outside of these methods.
If that is incompatible with your criteria, consider using Provider.of(context, listen: false). It does the same thing, but without these added restrictions (but unsafe).
DON'T call [read] inside build if the value is used only for events:
Well how can I get this work?
EDIT:
Is this also good to go?
child: BlocListener<BlocA, BlocAState>(
listener: (context, state) {
// TODO: implement listener
if (state is LiveeventFinishedState) {
print('LiveeventFinishedState');
BlocProvider.of<BlocB>(context).add(LoadJoinableEvent());
BlocProvider.of<BlocC>(context).add(LoadEventsEvent());
}
},
you don't need to create a new bloc as your RootScreen
seems to be a a child node of AppWrapper
in the widget tree, Provider
will provide data (in this case EventsBloc) to all of its children.
You can access the bloc data by using context.read()
and add a new event as below:
BlocBuilder<DifferentBloc, DifferentBlocState>(
builder: (context, state) {
if (state.navbarItem == FMNavigation.home) {
// you can access the bloc just fine
context.read<EventsBloc>().add(LoadEventsEvent());
return HomeScreen(),
} else if (state.navbarItem == FMNavigation.chat) {