使用 Firestore 流进行颤振分页

时间:2021-07-07 06:15:36

标签: flutter dart google-cloud-firestore stream

如何在flutter(在本例中为flutter web)上使用firestore流正确实现分页? 我目前使用 bloc 的方法很可能是错误的,就像这样

加载下一页时在 bloc 上调用的函数,请注意,每次调用该函数时,我都会将状态的 lastPage 变量增加 1:

Stream<JobPostingState> _loadNextPage() async* {
yield state.copyWith(isLoading: true);
try {
  service
      .getAllDataByClassPage(state.lastPage+1)
      .listen((List<Future<DataJob>> listDataJob) async {
    List<DataJob?> listData = [];
    await Future.forEach(listDataJob, (dynamic element) async {
      DataJob data= await element;
      listData.add(data);
    });
    bool isHasMoreData = state.listJobPostBlock.length!=listData.length;
    //Update data on state here
  });
} on Exception catch (e, s) {
  yield StateFailure(error: e.toString());
}}

调用获取流数据的函数

Stream<List<Future<DataJob>>> getAllDataByClassPage(
      String className, int page) {
    Stream<QuerySnapshot> stream;
    if (className.isNotEmpty)
      stream = collection
          .orderBy('timestamp', "desc")
          .where('class', "==", className).limit(page*20)
          .onSnapshot;
    else
      stream = collection.onSnapshot;

    return stream.map((QuerySnapshot query) {
      return query.docs.map((e) async {
        return DataJob.fromMap(e.data());
      }).toList();
    });
  }

使用这种方法它可以按预期工作,当我加载下一页并仍在侦听流时加载的数据增加,但我不知道这是否是正确的方法,因为它替换了流是否可能读取数据两次并结束让我的阅读依赖于 firestore 比不使用分页要多得多。非常感谢任何建议,谢谢。

1 个答案:

答案 0 :(得分:1)

您的方法确实不是最好的,并且随着您的扩展,您的成本会更高。我会在你的鞋子里做的是创建一个代表你的流的全局变量,这样你就可以操纵它。我看不到您的所有代码,因此我将尽可能通用,以便您可以将其应用到您的代码中。

首先让我们将流控制器声明为可以保存流值的全局变量:

StreamController<List<DocumentSnapshot>> streamController = 
    StreamController<List<DocumentSnapshot>>();

之后,我们需要将您的 getAllDataByClassPage 函数更改为以下内容:

async getAllDataByClassPage(String className) {
    Stream stream = streamController.stream;
    //taking out of the code your className logic
    ...
    if(stream.isEmpty){
         QuerySnapshot snap = await collection.orderBy('timestamp', "desc")
                                              .where('class', "==", className)
                                              .limit(20) 
                                              .onSnapshot
         streamController.add(snap.docs);
    }else{
         DocumentSnapshot lastDoc = stream.last;
         QuerySnapshot snap = await collection.orderBy('timestamp', "desc")
                                              .where('class', "==", className)
                                              .startAfterDocument(lastDoc)
                                              .limit(20)
                                              .onSnapshot;
         streamController.add(snap.docs);
    }
  }

之后,您需要做的就是调用 streamController.stream;

注意:我没有测试这段代码,但这是您应该尝试做的一般理想。