Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Stream/Bloc/Repository/Firebase data flow Flutter

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 the Model class there is a toEntity() and a fromEntity() conversion method, and in the Entity class there is a fromSnapshot() and a toDocument() conversion method. I don't see what's the point here. Is it really necessary? What's wrong with doing the conversion directly in the Model 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 at AppStart is LoadTodos.

BlocProvider<TodosBloc>(
          create: (context) {
            return TodosBloc(
              todosRepository: FirebaseTodosRepository(),
            )..add(LoadTodos());

In the mapEventToState() method of TodoBloc 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 the firebase_database package that has a FirebaseList 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.

like image 804
Vincenzo Avatar asked Feb 23 '20 16:02

Vincenzo


1 Answers

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.

  1. todos() is the Stream coming from Firebase and returns a List<Todo>.
  2. _mapLoadTodosToState() is the bloc method that attach a bloc listener to todos() and in the .listen(onData) callback, it sends to the bloc an TodosUpdated(todos) event containing the latest list.
  3. TodosUpdated(todos) gets mapped to _mapTodosUpdatedToState, which yields TodosLoaded(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

like image 180
Vincenzo Avatar answered Nov 16 '22 19:11

Vincenzo