Riverpod: пересчитать поставщика, предоставляющего список предметов при получении обновлений.

У меня есть простой пример использования, когда я пытаюсь пересчитать поставщика, предоставляющего список элементов при наблюдении за поставщиком элементов следующим образом:

final itemProvider = StateProvider<Item>((ref) {
    return Item() ;
});

final itemListProvider = Provider<List<Item>>((ref) {
 watch(itemProvider);
...//do something to compute new list
 return computedList ;
});

Я хочу, чтобы itemListProvider автоматически пересчитывался при изменении состояния itemProvider извне, чтобы itemListProvider продолжал добавлять новые элементы в существующий список, который он предоставляет. Есть ли способ добиться этого указанным выше способом с помощью Riverpod? Я знаю, что могу использовать StateNotifierProvider или StateProvider и обновить itemList с помощью вызова назначения состояния, но я с нетерпением жду возможности сделать это реактивно.

Любая помощь или руководство приветствуются. Спасибо!


person Akash Gorai    schedule 19.04.2021    source источник


Ответы (1)


Это легко сделать с помощью одного StateNotifierProvider.

class ItemList extends StateNotifier<List<Item>> {
  ItemList() : super([]);

  static final provider = StateNotifierProvider<ItemList, List<Item>>((ref) => ItemList());

  Item _current = Item();
  Item get current => _current;

  void addItem(Item item) {
    _current = item;
    state = [...state, item];
  }
}

Использование:

// Add an item, which updates the current item
watch(ItemList.provider.notifier).addItem(item);

// Get the current item
final currentItem = watch(ItemList.provider.notifier).current;

// Get the List<Item> from state
final itemList = watch(ItemList.provider);

Если вы действительно хотите избежать StateNotifierProvider, вы можете сделать следующее, но я настоятельно рекомендую вам использовать первый подход. В любом случае:

final itemProvider = StateProvider<Item>((ref) => Item());

final itemListProvider = StateProvider<List<Item>>((ref) => []);

final computedListProvider = Provider<List<Item>>((ref) {
  final item = ref.watch(itemProvider);
  final itemList = ref.watch(itemListProvider);
  WidgetsBinding.instance?.addPostFrameCallback((_) {
    if (itemList.state.contains(item.state)) return;
    itemList.state = [...itemList.state, item.state];
  });

  return itemList.state;
});
person Alex Hartford    schedule 20.04.2021
comment
Спасибо за ответ! Однако я искал лучшую альтернативу или, возможно, функцию, в которой поставщик мог бы вычислять себя с существующими и новыми данными без внешних вызовов состояния addToList. Можно ли это как-то сделать? - person Akash Gorai; 20.04.2021
comment
Я не уверен, зачем вам все усложнять таким образом. Не могли бы вы расширить свой вопрос, почему StateNotifier не работает для вашего варианта использования? - person Alex Hartford; 20.04.2021
comment
К сожалению, нет :( - person Akash Gorai; 20.04.2021
comment
@AkashGorai Хорошо, я добавил альтернативное решение, которое завершает то, что вы начали в своем вопросе. - person Alex Hartford; 20.04.2021
comment
Я не понимал, что здесь можно использовать postFrameCallback: D. - person Akash Gorai; 21.04.2021
comment
Почему вы предлагаете использовать подход StateNotifier? Я знаю, что это рекомендуется в примерах, но ... я хотел, чтобы поставщик itemList содержал логику того, что делать с самими данными. Разве реактивное добавление элементов не лучше, чем вызов метода для этого? - person Akash Gorai; 21.04.2021
comment
Я имею в виду, что оба способа решают одну и ту же задачу с помощью одного вызова функции, но подход уведомлений чище, лаконичнее и менее подвержен ошибкам. - person Alex Hartford; 21.04.2021
comment
@AkashGorai Если это решило вашу проблему, отметьте это как принятый ответ. Думаю, будущим читателям будет полезно увидеть два подхода к подобной проблеме. - person Alex Hartford; 22.04.2021
comment
Я не уверен, насколько чистым является второе решение для моего варианта использования / запроса. Вероятно, он выполняет свою работу, и я отмечаю это правильно. Однако это определенно очень взломано и не рекомендуется. - person Akash Gorai; 22.04.2021