如何在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 比不使用分页要多得多。非常感谢任何建议,谢谢。
答案 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;
注意:我没有测试这段代码,但这是您应该尝试做的一般理想。