I have declared all my blocs in main.dart with MultiBlocProvider. One of my Blocs is a SharedStoreBloc with AddItemEvent and LoadItemEvent. I use this to store temporary items such as document id's of documents, that I will use again throughout my app.
In the example below:
My problem is, that when I fire the SharedStoreItemLoadEvent in section_view.dart, both BlocListeners in both the views will fire.
As the value I get in section_view class is a different one, then in the course_view class, the course_view class fails, as it received the value loaded in the section_view class, as both receive the same state.
One option would be, to move the creation of the SharedStoreBloc from main.dart into each the section_view.dart, and course_view.dart. I assume that then this would not trigger both BlocListeners in both classes to fire. But I would have to create the SharedStoreBloc in each of the classes I'm using it, which wouldn't be a very nice solution.
Is there a better way to make sure, only the BlocListener receives the state, within the class the event is triggered?
Below the snippets of the code.
main.dart
void main() async {
BlocSupervisor.delegate = SimpleBlocDelegate();
runApp(TeachApp());
}
class TeachApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MultiBlocProvider(
providers: [
BlocProvider<AuthenticationBloc>(
create: (context) {
return AuthenticationBloc(
userRepository: FirebaseUserRepository(),
)..add(AppStarted());
},
),
BlocProvider<SchoolBloc>(
create: (context) {
return SchoolBloc(
schoolRepository: FirebaseSchoolRepository(),
);
},
),
BlocProvider<CourseBloc>(
create: (context) {
return CourseBloc(
courseRepository: FirebaseCourseRepository(),
);
},
),
BlocProvider<SectionBloc>(
create: (context) {
return SectionBloc(
sectionRepository: FirebaseSectionRepository(),
);
},
),
BlocProvider<SharedStoreBloc>(
create: (context) {
return SharedStoreBloc(
sharedStoreRepository: SharedDbRepository(),
);
},
),
],
child: MaterialApp(
...
course_view.dart
class CourseView extends StatefulWidget {
@override
State<StatefulWidget> createState() => _CourseViewState();
}
class _CourseViewState extends State<CourseView> {
SharedStoreBloc _sharedStoreBloc;
CourseBloc _courseBloc;
@override
void initState() {
// Assign the blocs to the variables
_sharedStoreBloc = BlocProvider.of<SharedStoreBloc>(context);
_courseBloc = BlocProvider.of<CourseBloc>(context);
// Dispatch events on page load
_sharedStoreBloc.add(SharedStoreItemAddEvent(PrefKeys.schoolId, "sfjklsdjklsfd"));
// FIRE THE LOAD EVENT, WHICH WILL YIELD SHAREDSTOREITEMLOADEDSTATE
_sharedStoreBloc.add(SharedStoreItemLoadEvent(PrefKeys.schoolId));
super.initState();
}
@override
Widget build(BuildContext context) {
// build ui
return Scaffold(
appBar: AppBar(
title: Text("Courses")
),
body: BlocListener(
bloc: _sharedStoreBloc,
listener: (context, state) {
// THIS IS WHERE STUFF FAILS
if(state is SharedStoreItemLoadedState) {
// load the courses assigned to the school
_courseBloc.add(LoadCoursesOfSchoolEvent(state.value));
}
},
child: BlocBuilder<CourseBloc, CourseState>(
bloc: _courseBloc,
builder: (context, state) {
if(state is CoursesLoadedState) {
section_view.dart
class SectionView extends StatefulWidget {
@override
State<StatefulWidget> createState() => _SectionViewState();
}
class _SectionViewState extends State<SectionView> {
SharedStoreBloc _sharedStoreBloc;
SectionBloc _sectionBloc;
@override
initState(){
_sharedStoreBloc = BlocProvider.of<SharedStoreBloc>(context);
_sectionBloc = BlocProvider.of<SectionBloc>(context);
// FIRE THE LOAD EVENT, WHICH WILL YIELD SHAREDSTOREITEMLOADEDSTATE
_sharedStoreBloc.add(SharedStoreItemLoadEvent(PrefKeys.courseId));
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Sections")
),
body: Text("here we are")
);
}
When course and section fire the SharedStoreItemLoadEvent with different data and they expect different data, could it be the you actually need two different SharedStores? One for each of course and section?
As I understand, Blocs are there for exactly this purpose: Sharing the same state between different components. If you start to distinguish between items in the Listener (with a condition as in https://pub.dev/documentation/flutter_bloc/latest/flutter_bloc/BlocListener-class.html), it smells a little like you need to divide SharedStore.
Thanks Valentin for your answer. Much appreciated. I've read what I can do with "condition", but didn't see, how I could use it in my use-case . Therefore agreed, looks like dividing the shared store is the way to go. I hoped I can prevent some boilerplate code, but it's fine, if this is considered to be the best practice. Will close this issue.
Most helpful comment
When course and section fire the SharedStoreItemLoadEvent with different data and they expect different data, could it be the you actually need two different SharedStores? One for each of course and section?
As I understand, Blocs are there for exactly this purpose: Sharing the same state between different components. If you start to distinguish between items in the Listener (with a condition as in https://pub.dev/documentation/flutter_bloc/latest/flutter_bloc/BlocListener-class.html), it smells a little like you need to divide SharedStore.