如何从 Riverpod 中的另一个提供程序修改 StateNotifier 提供程序的状态?

neo*_*x97 5 android firebase flutter riverpod

我对 flutter 和 Riverpod 很陌生,所以如果问题不清楚,我非常抱歉,如果是这种情况,请告诉我

我有 2 个提供程序,一个监听 FireStore 集合的实时更改,另一个是列表服务,用于处理从 FireStore 接收的实际项目列表。我想将收到的列表添加到 itemList 中,然后通知监听 itemListProvider 的小部件,以便可以重建 listview

项目列表状态通知程序提供者

final itemListProvider =
    StateNotifierProvider<ItemListService, List<Item>>(
        (ref) => ItemListService([]));
Run Code Online (Sandbox Code Playgroud)

实时监听器

final firestoreListUpdateWatcher = Provider((ref) {
  //Listens to a stream which provide query snapshot, this works as intended
  final firestoreListWatcher = ref.watch(firestoreListProvider);
  
  //using `ref.watch(itemListProvider.notifier)` because i want to be able 
  //to change the state from this provider
  final itemListProvider = ref.watch(itemListProvider.notifier);
  
  firestoreLisUpdateWatcher.when(
      data: (value) {
          for (int i = 0; i < value.docChanges.length; i++) {
            QueryDocumentSnapshot currentQuery = value.docs[i];
            //current item in list
            ListItem item = fireStoreList.fromMap(currentQuery.data());

            //add current item to the ListService 
            itemListProvider.add(item);
          }
      },
      loading: () {},
      error: (err, stack) {});
});
Run Code Online (Sandbox Code Playgroud)

项目列表 服务等级

class ItemListService extends StateNotifier<List<Item>> {

  ItemListService(List<Item> itemList):super(itemListList ?? []);

  void add(Item it) {
    state = [...state, it];
  }

  //more methods modifying the list....
}
Run Code Online (Sandbox Code Playgroud)

在我的小部件的构建函数中,我只想监听 itemListProvider 的更改并根据当前状态重新创建列表

这不起作用,当对列表进行更改时,我的小部件不会重建。我相信它不起作用的原因是因为当我使用ref.watch(itemListProvider.notifier)即时创建的新实例在“firestoreListUpdateWatcher”中创建“观察器”时,我的小部件没有监听该实例,因此在发生更改时不会收到通知。这个假设正确吗?

另外,我怎样才能实现这种行为(修改另一个提供商的列表)

有没有更好的方法来设计我的应用程序来避免这种限制?

在此先感谢您的帮助

Edw*_*nZN 4

正如您所说,ref.watch 正在重新创建提供程序,这就是为什么您看不到更改的原因,您可以使用当前逻辑执行的操作是观看流而不是提供程序,并使用相同的侦听器更新状态itemListProvider 无需创建另一个 Provider:

/// This is your StateNotifierProvider
final itemListProvider = StateNotifierProvider.autoDispose<ItemListService, List<Item>>((ref) {
  //Listen to the stream itself instead of the value hold by the provider
  final firestoreListStream = ref.watch(firestoreListProvider.stream);
  
  //Create the instance of your StateNotifier
  final itemListProvider = ItemListService([]);

  /// subscribe to the stream to change the state accordingly
  final subscription = firestoreListStream.listen((value) {
          for (int i = 0; i < value.docChanges.length; i++) {
            QueryDocumentSnapshot currentQuery = value.docs[i];
            //current item in list
            ListItem item = fireStoreList.fromMap(currentQuery.data());

            //add current item to the ListService 
            itemListProvider.add(item);
          }
      });
  /// When you stop using this porvider cancel the subscription to the stream, to avoid memory leaks
  ref.onDispose(subscription.cancel);
  return itemListProvider;
});
Run Code Online (Sandbox Code Playgroud)

有了这个,您将不需要另一个提供者 ( firestoreListUpdateWatcher)

作为建议,我注意到您迭代 for 循环并单独添加它们,这将强制状态更新多次,我建议首先获取列表,然后使用 addAll 方法更新状态

final subscription = firestoreListStream.listen((value) {
   List<ListItem> items = [];
   for (int i = 0; i < value.docChanges.length; i++) {
       QueryDocumentSnapshot currentQuery = value.docs[i];
       //current item in list
       ListItem item = fireStoreList.fromMap(currentQuery.data());

       //add current item to the ListService 
       items.add(item);
   }
   ItemListService.addAll(items);
          
});
Run Code Online (Sandbox Code Playgroud)

并在您的 ItemsService 中创建 addAll 方法

void addAll(Iterable<Item> it) {
  state = [...state, ...it];
}
Run Code Online (Sandbox Code Playgroud)