Returning List from Firestore Listen callback

这一生的挚爱 提交于 2021-02-10 14:39:34

问题


I have a function in firebase that is intended to get all documents in a collection called history and add it to a list intended to be returned.

The problem is, and I think this is because .listen() is async, the list returned is always empty. I know the data is queried correctly because I can print the doc in the forEach function, but adding to a list outside doesn't work.

By the way, myStream is a snapshot of the history collection in FireStore.

Does my function need to be a Future? How can I make this work?

Here is my code:

List getHistory(String id) {
  List history;

  Firestore.instance.collection(id).snapshots().listen((data) {
    data.documents.forEach(
      (doc) => history.add(doc['day']),
    );
  });

  return history;
}

回答1:


Yes, your function will have to return a Future.
As you correctly pointed out, the way Firestore data is retrieved is asynchronous. This means that whereever you want to use this data, you will have to await a Future.
If you want to do this in your UI, you can just make use of Flutter's FutureBuilder.

However, firstly you need to refactor your getHistory function.
You will not be able to use the snapshots function if you just want to get the history once. If you do want to use real-time updates, then you can just translate everything I say to a StreamBuilder, but then you cannot return your List, you could only yield it (I will just include an example implementation at the end).
Having said that, I am going to use the getDocuments method for the FutureBuilder example.

Get data once

Future<List> getHistory(String id) async {
  List history;

  final List<DocumentSnapshot> documents = 
      (await Firestore.instance.collection(id).getDocuments()).documents;

  history = documents.map((documentSnapshot) => documentSnapshot['day']).toList();

  return history;
}

Notice that I added the async keyword to be able to await the getDocuments call and wrapped the return type in a Future. I used the List.map method to map the DocumentSnapshot's to your day value (I also changed your myStream to a Firestore call because I cannot know the objects you actually use in your class, thus you will have to exchange that with how you access your Firestore collection).
In the next step, I will include an example implementation of how you would use this function in your UI using FutureBuilder:

FutureBuilder(
  future: getHistory(id),
  builder: (BuildContext context, AsyncSnapshot<List> snapshot) {
    if (snapshot.hasError) return Text('${snapshot.error}');
    if (!snapshot.hasData) return CircularProgressIndicator();

    return ListView(
      children: snapshot.data
          .map((day) => ListTile(
                title: Text('$day'),
              ))
          .toList(),
    );
  },
);

I simply used a ListView to demonstrate how you could use your list of data in your UI.

Real-time updates

Because I mentioned it earlier, here would be an example implementation for having real-time updates using Stream (you would have to exchange your FutureBuilder with a StreamBuilder if you wanted to use it in your UI):

Stream<List> getHistory(String id) {
  final Stream<QuerySnapshot> documents = Firestore.instance.collection(id).snapshots();

  return documents.map((querySnapshot) {
    List history;
    final documents = querySnapshot.documents;

    history = documents.map((documentSnapshot) => documentSnapshot['day']);

    return history;
  });
}

In this case, I am just mapping the Stream, which will apply the mapping operation for every data event. I mentioned yield above, but it is not necessary to use that here. You could use yield in the following manner, which would be closer to your initial implementation:

Stream<List> getHistory(String id) async* {
  await for (QuerySnapshot querySnapshot in Firestore.instance.collection(id).snapshots()) {
    List history;
    final documents = querySnapshot.documents;

    history = documents.map((documentSnapshot) => documentSnapshot['day']);

    yield history;
  }
}

This is probably just confusing and it is completely unnecessary here, so just ignore it :)



来源:https://stackoverflow.com/questions/57263974/returning-list-from-firestore-listen-callback

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!