簡體   English   中英

僅當代碼在提供程序中時,Riverpod 提供程序列表才會從 firebase 更新

[英]Riverpod provider list updates from firebase only if the code is in the provider

我有一個 Riverpod Streamprovider,它管理如何將許多不同的 Firebase 文檔呈現給用戶。 然后用戶可以訪問每個文檔,進行一些更改並返回到他們的文檔列表。 他們完成后,更改該文檔的行應該顯示一個勾號。 唯一的問題是這些文檔在不同的集合中,每個文檔都有自己的標識符。 所以它不像流式傳輸整個集合那么容易,我的 function 需要獲取每個項目的標識符,然后獲取要發送給用戶的文檔列表。

我有代碼,所以它“正常工作”,但我無法解決的是為什么當所有代碼都在提供者內部時更新記錄有效,而當提供者將其稱為外部代碼時。 例如,這個 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 數據庫 class 一起使用。所以我嘗試拆分它,所以現在在我的 firebase crud class 中我有幾乎相同的代碼:

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 的更新不會觸發對 ui 的任何更新,因此當用戶返回到他們的文檔列表時,他們看不到已經處理過的文檔。 我一直在房子周圍試圖弄清楚我做錯了什么但看不到它。

編輯:只是快速編輯以防萬一,但這適用於 FlutterWeb,而不是 iOS 或 Android

我離開這個以防其他人有同樣的問題。 這個項目的真正問題是數據庫結構不符合目的,進一步的限制是不能在數據庫中復制數據。

最簡單的解決方案(如果您碰巧正在閱讀這篇文章是因為您解決了類似的問題)是在用戶自己的集合中制作一份用戶應該有權訪問的文檔的副本,然后可以將其作為整個集合進行流式處理。 無論如何,檢查哪些文檔已經被用戶查看過,哪些沒有被用戶查看過,總是必須通過管理員帳戶來完成,所以這似乎不會招致懲罰。

盡管如此,我最終還是管理了我的特定數據回購

1 制作一個簡單的提供者到 stream 單個文檔

 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 的構建方法中觀察了 ListProvider。 這為您提供了各個頁面的 StreamProvider 列表。 最后,我使用 ListView 獲取每個 StreamProvide (listofProviders[index]) 並使用 provider.when(...

然而,我不知道這種方法會變得多么脆弱!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM