Stream/Bloc/Repository/Firebase data flow Flutter
Ok, I I think I understood the logic behind it, but if you see that I didn't get it right please correct me as at this stage of getting into a new paradigm is very important not to carry any misconceptions.
todos()
is the Stream coming from Firebase and returns aList<Todo>
._mapLoadTodosToState()
is the bloc method that attach a bloc listener totodos()
and in the.listen(onData)
callback, it sends to the bloc anTodosUpdated(todos)
event containing the latest list.TodosUpdated(todos)
gets mapped to_mapTodosUpdatedToState
, which yieldsTodosLoaded(event.todos)
, the new state that BlocProvider uses to build the UI.
Thank you and I hope this will help others struggling to master BloC pattern at a more complex level. Cheers
Vincenzo
At age of 40 an accident forced me in bed for a few months and I realised that I wanted point my life in a different direction to really fulfil my purpose in life, help others and help making this planet a better place. I love to create stuff and I constantly have perhaps too many ideas. I'm now launching a bicycle related start-up. I got back into coding after 25 years away from it as it was a fundamental skill to get updated to get the project started and since then I'm working on the start-up's products. I first learned Swift as it seemed the easiest language I could learn at fast pace, but when Apple created SwiftUI framework ( Flutter copycat A.F.A.I.K ) I decided to move away from Swift the obvious choice has been learning Flutter ( the original ). So happy I made the transition and I'm not looking back.
Updated on December 08, 2022Comments
-
Vincenzo over 1 year
I'm starting with flutter as I want to port my swift app to Flutter, but I'm getting stuck understanding the pattern Bloc/Repository/Firebase as I'm following the tutorial https://bloclibrary.dev/#/flutterfirestoretodostutorial dough I use the real time database, not Firestore. My swift app is basically a map where you can add Alerts at your actual coordinates. The Alert get sent to Firebase and the firebase observer on the map updates the map showing the just added alert. The above tutorial should help me porting my app. I'm just not sure I do understand the logic behind the code. My concerns are 2:
First. There is an
Entity
layer between the model object and the firebase object. It is explained that this will facilitate having different Data providers, but I don't really see it facilitating anything. In theModel
class there is atoEntity()
and afromEntity()
conversion method, and in theEntity
class there is afromSnapshot()
and atoDocument()
conversion method. I don't see what's the point here. Is it really necessary? What's wrong with doing the conversion directly in theModel
class , having different methods for each Data provider?Second. Inside the
TodoBloc
I can't follow the logic. The first event that is sent to the bloc atAppStart
isLoadTodos
.BlocProvider<TodosBloc>( create: (context) { return TodosBloc( todosRepository: FirebaseTodosRepository(), )..add(LoadTodos());
In the
mapEventToState()
method ofTodoBloc
that event gets mapped to this Stream:Stream<TodosState> _mapLoadTodosToState() async* { _todosSubscription?.cancel(); _todosSubscription = _todosRepository.todos().listen( (todos) => add(TodosUpdated(todos)), ); }
So far so good. As I understand this subscribes to the
todos()
Stream ()@override Stream<List<Todo>> todos() { return todoCollection.snapshots().map((snapshot) { return snapshot.documents .map((doc) => Todo.fromEntity(TodoEntity.fromSnapshot(doc))) .toList(); }); }
and this should be the equivalent of the firebase observer in my swift app. It this part inside the
listen
closure I'm not sure to understand:(todos) => add(TodosUpdated(todos))
.This sends to itself (TodoBloc) a
TodosUpdated
event on which the bloc will map this Stream:Stream<TodosState> _mapTodosUpdatedToState(TodosUpdated event) async* { yield TodosLoaded(event.todos); }
which is this:
class TodosLoaded extends TodosState { final List<Todo> todos; const TodosLoaded([this.todos = const []]); @override List<Object> get props => [todos]; @override String toString() => 'TodosLoaded { todos: $todos }'; }
Is this the actual list of Firebase objects? Does the
todos()
Stream return the entire node every time a new object is added in Firebase? In my swift app the observer returns only the.childAdded
after the first download of the node. Should I use thefirebase_database
package that has aFirebaseList
class(https://pub.dev/documentation/firebase_database/latest/ui_firebase_list/FirebaseList-class.html) that will just return a List on any change on the node as my observers do in my swift app? Sorry for this very long and messy question, but I'm quite lost here starting with bloc pattern. Thank you very much for your time and help.