AngularFire2无限滚动

2023-12-21

我正在尝试使用 Ionic2 和 Firebase 实现无限滚动。

我使用 AngularFire2。我想做的是将新项目添加到获取的列表中,而不是重新加载整个列表。

let query$:Observable<any> = this.af.database.list(`quests/`, {
    query: {
        orderByChild: 'date_published',
        limitToFirst: this.recentChunkLimit$ //Subject where I push new limit length
    }
}).publishReplay(1).refCount();

However, when I query list like that, the whole list is reloaded each time via websockets making each next update slower and slower. Here is a screenshot of Network websockets tab: websockets And also I noticed that requests are made 2 times for each next chunk (though I put publishReplay). And it is happening in all apps where I used AngularFire2. I might misunderstand something though. I definitely need some clarification.

//==========编辑============

Now, I somehow managed to implement what I want without reloading the whole list each time. Not the best implementation but it works. Basically, I created an observable array and load new values into it by subscribing to the next chunk observable (where I also get the last element to start with). However the later problem still remains - in the sockets display I get data requested 2 times. enter image description here


使用可观察量query选项并不是那样工作的。底层 SDK 中没有工具可以动态修改查询的limitToFirst在 AngularFire2 中没有办法做到这一点。

每次观察到query选项发出一个新值,创建一个新的 Firebase 引用。您可以在来源在这里 https://github.com/angular/angularfire2/blob/2.0.0-beta.7/src/database/firebase_list_factory.ts#L36-L93.

但是,可以通过执行以下操作来创建表示无限列表的可观察量:

import { Observable } from "rxjs/Observable";
import { Subject } from "rxjs/Subject";
import rxjs/add/observable/defer";
import rxjs/add/observable/zip";
import rxjs/add/operator/concatMap";
import rxjs/add/operator/filter";
import rxjs/add/operator/first";
import rxjs/add/operator/map";
import rxjs/add/operator/scan";
import rxjs/add/operator/share";
import rxjs/add/operator/startWith";

const pageSize = 100;
let notifier = new Subject<any>();
let last: Observable<any>;

let infiniteList = Observable

  // Use zip to combine the notifier's emissions with the last
  // child value:

  .zip(notifier, Observable.defer(() => last))

  // Use concatMap to emit a page of children into the
  // composed observable (note that first is used to complete
  // the inner list):

  .concatMap(([unused, last]) => this.af.database.list("quests", {
      query: {

        // If there is a last value, start at that value but ask
        // for one more:

        limitToFirst: last ? (pageSize + 1) : pageSize,
        orderByChild: "date_published",
        startAt: last
      }
    })
    .first()
  )

  // Use scan to accumulate the page into the infinite list:

  .scan((acc, list) => {

    // If this isn't the initial page, the page was started
    // at the last value, so remove it from the beginning of
    // the list:

    if (acc.length > 0) {
      list.shift();
    }
    return acc.concat(list);
  }, [])

  // Use share so that the last observable (see below) doesn't
  // result in a second subscription:

  .share();

// Each time a page is emitted, map to its last child value so
// that it can be fed back into the composed infinite list:

last = infiniteList
  .filter((list) => list.length > 0)
  .map((list) => list[list.length - 1].date_published)
  .startWith(null);

infiniteList.subscribe((list) => console.log(list));

// Each time the notifier emits, another page will be retrieved
// and added to the infinite list:

notifier.next();
notifier.next();
notifier.next();

这会起作用,但如果您订购的子项具有重复值,则 AngularFire2 将无法可靠地分页结果,直到这个问题 https://github.com/angular/angularfire2/issues/362重新打开并解决。

结果列表是静态的。也就是说,如果数据库发生更改,已分页到列表中的子项将不会更新。实现动态列表更具挑战性,因为基于限制的分页机制很容易影响重复和丢失的子项。


自从写完这个答案以来,我已经在我开源的 Firebase 可观察对象库中提供了正向和反向、非实时和实时无限列表可观察对象的经过测试的实现。看这个 GitHub 存储库 https://github.com/cartant/firebase-thermite/tree/master/source/observable/database.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

AngularFire2无限滚动 的相关文章

随机推荐