Как получить все документы из коллекции firebase во Flutter с помощью пакета Riverpod?

Я использую пакет провайдера, и у меня есть провайдер, который получает свое начальное значение из идеи глобальной переменной, которая представляет собой список данных json и имеет тип List ‹Map‹ String, dynamic ››.

Ниже приведен код для ожидаемой работы.

final ideasListProvider = StateNotifierProvider<IdeaList>((ref) {
  return IdeaList([for (var i in ideas) Idea.fromJson(i)]);
});

Теперь я пытаюсь заменить идею переменной и вместо этого использовать список документов, который я получаю из коллекции, которая есть у меня на firebase.

Но я не знаю, как действовать дальше.

Вот второй провайдер, который извлекает из хранилища моментальных снимков.

final firbaseIdeaProvider = StreamProvider.autoDispose((ref) {
  return FirebaseFirestore.instance.collection('ideas').snapshots();
});

Что мне теперь делать? Остальная часть моего кода зависит от ideaListProvider, поэтому мне придется каким-то образом предоставить ему список документов из коллекции идей на firebase.


person Dexter    schedule 22.10.2020    source источник


Ответы (1)


Хорошие новости, вы на правильном пути. Во-первых, вы, скорее всего, захотите сопоставить данные своего хранилища с вашей моделью данных. Это может быть выполнено путем создания нового потока, отображаемого из потока данных вашего хранилища:

final firebaseIdeaProvider = StreamProvider.autoDispose<List<Idea>>((ref) {
  final stream = FirebaseFirestore.instance.collection('ideas').snapshots();
  return stream.map((snapshot) => snapshot.docs.map((doc) => Idea.fromJson(doc.data())).toList());
});

Теперь осталось только прочитать ваш StreamProvider. Пример, который будет обрабатывать загрузку, ошибку и новые состояния данных, может быть следующим (с hooks_riverpod):

class IdeasExample extends HookWidget {
  const IdeasExample({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Ideas Example'),
      ),
      body: useProvider(firebaseIdeaProvider).when(
        loading: () => const Center(child: CircularProgressIndicator()),
        error: (err, stack) => Center(child: Text(err.toString())),
        data: (ideas) {
          return ListView.builder(
            itemCount: ideas.length,
            itemBuilder: (_, index) {
              return ListTile(
                title: Text(ideas[index].toString()),
              );
            },
          );
        },
      ),
    );
  }
}

Без крючков:

class IdeasExample extends ConsumerWidget {
  const IdeasExample({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context, ScopedReader watch) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Ideas Example'),
      ),
      body: watch(firebaseIdeaProvider).when(
        loading: () => const Center(child: CircularProgressIndicator()),
        error: (err, stack) => Center(child: Text(err.toString())),
        data: (ideas) {
          return ListView.builder(
            itemCount: ideas.length,
            itemBuilder: (_, index) {
              return ListTile(
                title: Text(ideas[index].toString()),
              );
            },
          );
        },
      ),
    );
  }
}
person Alex Hartford    schedule 22.10.2020
comment
Привет, спасибо за ответ. Я пробовал это, но это вызывает исключение [core/no-app] No Firebase App '[DEFAULT]' has been created - call Firebase.initializeApp() Но дело в том, что я уже инициализировал Firestore в файле mian.dart. Любая идея, что может быть причиной этого? - person Dexter; 23.10.2020
comment
Вы как следует этого ждали? Future<void> main() async { await Firebase.initializeApp(); ... } - person Alex Hartford; 23.10.2020
comment
Что ж, оказывается, я забыл добавить ожидание перед Firebase.initializeApp (). Теперь код работает правильно. Если бы вы могли помочь мне с последним этим, я также хочу использовать это значение внутри другого поставщика, а именно этого .final ideasListProvider = StateNotifierProvider<IdeaList>((ref) { return IdeaList([for (var i in ideas) Idea.fromJson(i)]); }); Но после возврата [for (var i in ideas) Idea.fromJson(i)] внутри IdeaList я хочу вернуть список, который мы получаем от firebaseIdeaProvider. Возможно ли этого добиться? - person Dexter; 23.10.2020
comment
Это возможно, хотя я немного не понимаю, зачем вам это нужно. Я думаю, что, вероятно, есть более простые способы выполнить то, что вы пытаетесь сделать, просто обновив свои Ideas в Firestore, и поток будет обслуживать самые последние значения, а не манипулировать ими локально в StateNotifier. - person Alex Hartford; 23.10.2020
comment
Я хочу иметь возможность фильтровать список идей, когда пользователь нажимает кнопку с помощью Enum. Перед внедрением firebase я наблюдал за состоянием ideaProvider и перечисления в другом провайдере и отображал элементы на основе этого. Итак, было интересно, можно ли это как-то сделать, используя значение, которое я получаю от ideaFirebaseProvider? - person Dexter; 24.10.2020