Разбивка страниц Flutter Firestore в реальном времени с использованием нескольких объединенных потоковых слушателей

Я хочу создать экран разбиения на страницы, используя Bloc, из базы данных Firestore. Экран должен обновляться при изменении документа.

Мой FirestoreProviderApi получает запросы на выборку от блока Bloc. После извлечения документов из Firestore он отправляет их обратно в блок с помощью Stream.

FirestoreProviderApi:

  final _pollOverviewStreamController = BehaviorSubject<QuerySnapshot>();

  @override
  Stream<QuerySnapshot> getOverviewPolls<QuerySnapshot>() =>
      _pollOverviewStreamController.asBroadcastStream().cast();

  @override
  Future<void> fetchFirstOverviewPolls() async {
    _overviewPollsRef.limit(5).snapshots().listen((querySnapshot) {
      _pollOverviewStreamController.add(querySnapshot);
    });
  }

  @override
  Future<void> fetchNextOverviewPolls() async {
    if (_pollOverviewStreamController.value.docs.isEmpty) return;

    final lastDoc = _pollOverviewStreamController.value.docs.last;
    _overviewPollsRef
        .startAfterDocument(lastDoc)
        .limit(5)
        .snapshots()
        .listen((querySnapshot) {
      _pollOverviewStreamController.add(querySnapshot);
    });
  }

При изменении документа я хочу обновить свой список документов.

Прямо сейчас, всякий раз, когда происходит изменение, к потоку добавляется новый QuerySnapshot (вместо замены старого). Есть ли способ объединить несколько слушателей в один и тот же поток, собирая только самые свежие данные?

вы можете объединить несколько потоков в один поток, который дает самые последние данные, используя RxDart.

Sathi Aiswarya 13.05.2022 10:56
ОбъединитьПоследнийпоток не является подходящим решением, так как я всегда прослушиваю изменения документа, а CombineLatestStream излучает, только если все потоки заканчиваются.
genericUser 13.05.2022 19:59

Кажется, то, что я ищу, невозможно. Я нашел альтернативный учебник, который объясняет, как решить эту проблему другим способом fillstacks.com/post/…

genericUser 13.05.2022 20:16
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
3
45
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Проблема решена.

Я нашел хорошую документацию о том, как реализовать разбиение на страницы в реальном времени с использованием Firestore (было реализовано, работает как шарм).

Реализация Youtube: Flutter и Firestore Пагинация в реальном времени.

Шаги высокого уровня:

  1. Создайте переменную состояние списка документов на уровне класса.
  2. Транслировать каждый раз весь список.
  3. Слушайте и повторяйте изменения моментальных снимков, а также обновить/добавить документы в основной список.
  4. Если список не пуст, то документ взять из последнего в списке.

Моя реализация:

final List<DocumentSnapshot> _overviewPolls = [];

@override
  Future<void> fetchOverviewPolls(
      [int firstFetchLimit = 1, int nextFetchLimit = 1]) async {

    Query overviewPollsQuery = _overviewPollsRef.limit(firstFetchLimit);

    if (_overviewPolls.isNotEmpty) {
      overviewPollsQuery = overviewPollsQuery
          .startAfterDocument(_overviewPolls.last)
          .limit(nextFetchLimit);
    }

    overviewPollsQuery.snapshots().listen((querySnapshot) {
      if (querySnapshot.docs.isNotEmpty) {
        for (final doc in querySnapshot.docs) {
          int index = _overviewPolls.indexWhere((d) => d.id == doc.id);
          // if already exists - update poll
          if (index >= 0) {
            _overviewPolls[index] = doc;
          }
          // if new document - add poll
          else {
            _overviewPolls.add(doc);
          }
        }

        _pollOverviewStreamController.add(_overviewPolls);
      }
    });
  }

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

Обратите внимание, что если вы используете orderBy при запросе вашего снимка, любое обновление в поле заказа приведет к переупорядочению всего списка элементов. Более того, в некоторых случаях он будет автоматически получать больше элементов (поскольку мы используем ограничение для каждого снимка, а список элементов переупорядочивается, некоторым снимкам может потребоваться получить больше элементов, чтобы заполнить его ограничение).

Другие вопросы по теме