AngularFire2无限滚动

Dan*_*nov 3 infinite-scroll firebase ionic2 angularfire2 angular

我正在尝试使用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();
Run Code Online (Sandbox Code Playgroud)

但是,当我查询这样的列表时,每次通过websockets重新加载整个列表,使每次下一次更新变得越来越慢.以下是网络websockets选项卡的屏幕截图: 的WebSockets 而且我注意到每个下一个块的请求都是2次(尽管我放了publishReplay).它发生在我使用AngularFire2的所有应用程序中.我可能会误解一些事情.我当然需要一些澄清.

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

现在,我以某种方式设法实现我想要的,而不是每次都重新加载整个列表.不是最好的实现,但它的工作原理.基本上,我创建了一个可观察的数组,并通过订阅下一个chunk observable(其中我也得到了最后一个元素)来加载新的值.然而,后来的问题仍然存在 - 在套接字显示中,我获得了2次请求数据.在此输入图像描述

car*_*ant 6

使用observables query选项只是不起作用.底层SDK中没有用于动态修改查询的工具,limitToFirst并且无法在AngularFire2中执行此操作.

每次可观察query选项发出新值时,都会创建一个新的Firebase引用.你可以在这里看到它.

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

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();
Run Code Online (Sandbox Code Playgroud)

这将有效,但如果您订购的子项具有重复值,AngularFire2将无法可靠地翻阅结果,直到重新打开并解决此问题.

结果列表是静态的.也就是说,如果数据库发生更改,则不会更新已列入列表的子项.实现动态列表更具挑战性,因为基于限制的分页机制可以轻松地实现重复和丢失的子项.


自从写完这个答案以来,我已经在我开源的Firebase可观察库中提供了正向和反向,非实时和实时无限列表可观察量的经过测试的实现.看到这个GitHub回购.