flutter 仅当代码在提供程序中时,才从firebase更新Riverpod提供程序列表

nhhxz33t  于 2023-01-31  发布在  Flutter
关注(0)|答案(1)|浏览(129)

我有一个Riverpod Streamprovider,它可以管理如何将大量不同的Firebase文档呈现给用户。然后用户可以访问每个文档,进行一些更改,并返回到他们的文档列表。一旦他们进行了更改,该文档的行应该有一个勾号显示。唯一的问题是,这些文档在不同的集合中,每个都有自己的标识符。所以它不像仅仅流传输整个集合那么容易,我的函数需要获取每个项的标识符,然后获取要发送给用户的文档列表。
我有代码,所以它“只是工作”,但我不能弄清楚的是,为什么更新记录工作时,所有的代码都在提供程序内部,而当提供程序调用它的外部代码。例如,这个StreamProvider工作,我想要的和更新的文档被识别

final outputStreamProvider = StreamProvider.autoDispose((ref) async* {
  final List<itemModelTest> itemList = [];
  final user = ref.watch(loggedInUserProvider);
  final uid = ref.watch(authStateProvider).value!.uid;
  for (String ident in user.value!.idents) {

# get each item by its own identifier

    final item = FirebaseFirestore.instance
        .collection('items')
        .where("ident", isEqualTo: ident)
        .limit(1)
        .snapshots();
    final result = await item.first;
    final test = result.docs[0];
    final itemItem = itemModelTest.fromFirebaseQuery(test, uid);
    itemList.add(itemItem);

# Listen for changes in the items

    item.listen((event) async {
      dev.log('event changed');
      for (var change in event.docChanges) {
        if (change.type == DocumentChangeType.modified) {
          itemModelTest updatedModel =
              itemModelTest.fromFirebaseQuery(test, uid);
          itemList
              .removeWhere((element) => element.title == updatedModel.title);
          itemList.add(updatedModel);
        }
      }
    });
  }
  yield itemList;
});

但是正如你所看到的,它包含了很多不属于那里的逻辑,而这些逻辑应该在我的firebase数据库类中,所以我试着将它拆分,现在在我的firebase crud类中,我有了几乎相同的代码:

Stream<List<itemModelTest>> itemsToReviewStream(LoggedInUser user, String uid) async*{
  final List<itemModelTest> itemList = [];
  for (String ident in user.idents) {
    final item = FirebaseFirestore.instance
        .collection('items')
        .where("ident", isEqualTo: ident)
        .limit(1)
        .snapshots();
    final result = await item.first;
    final test = result.docs[0];
    final itemItem = itemModelTest.fromFirebaseQuery(test, uid);
    itemList.add(itemItem);

    item.listen((event) async {
      dev.log('event changed ${event.docChanges.first.doc}');
      for(var change in event.docChanges){
        if(change.type == DocumentChangeType.modified){
          itemModelTest updatedModel = itemModelTest.fromFirebaseQuery(test, uid);
          itemList.removeWhere((element) => element.title == updatedModel.title);
          itemList.add(updatedModel);
        }
      }
    });
  }yield itemList;
}

我的StreamProvider现在看起来像这样

// Get a list of the currently logged in users papers to review
final testitemStreamProvider = StreamProvider.autoDispose((ref)  {
  final user = ref.watch(loggedInUserProvider).value;
  final uid = ref.watch(authStateProvider).value!.uid;
  return DataBase().itemsToReviewStream(user!, uid);
});

唯一的问题是使用第二种方法,firebase的更新不会触发用户界面的更新,所以当用户返回到他们的文档列表时,他们看不到哪些已经被处理过了。我一直在房子周围试图找出我做错了什么,但看不到。
编辑:只是一个快速编辑,以防万一,但这是为FlutterWeb,而不是iOS或Android

fiei3ece

fiei3ece1#

我离开这个以防其他人有同样的问题。这个项目的真实的问题是数据库结构不适合目的,进一步的限制是不要在数据库上重复数据。
最简单的解决方案(如果你碰巧阅读到这篇文章是因为你解决了一个类似的问题)是制作一个用户应该在他们自己的集合中访问的文档的副本,然后可以将其作为整个集合进行流传输。检查哪些文档已经和没有被用户查看总是要通过管理员帐户完成的,无论如何,所以这并不意味着会受到处罚。
为了管理我的特定数据存储库,我最终
1制作一个简单的提供程序来流式传输单个文档

final getSinglePageProvider = StreamProvider.family((ref, String  pageId){
   return DataBase().getSinglePage(pageId);});

然后,一旦您有了用户可以访问的所有文档的列表,就可以创建提供上述提供程序列表的提供程序

final simpleOutputsStreamsProvier = StreamProvider((ref) async* {
  final user = ref.watch(loggedInUserProvider);
  final items = user.value!.items;
  yield items.map((e) => ref.watch(getSinglePageProvider(e))).toList();
});

然后,您可以像平常一样在消费者中使用它,但它必须被“消费”两次。在我的例子中,我在ConsumerWidget的build方法中观察了ListProvider。它为您提供了各个页面的StreamProviders列表。最后,我使用ListView获取每个StreamProvide(listofProviders[index]),并使用provider展开它。当(...
然而,我不知道这种方法会变得多么脆弱!

相关问题