AngularFire2无限滚动 [英] AngularFire2 infinite scrolling
问题描述
我正在尝试使用Ionic2和Firebase实现无限滚动。
I'm trying to implement an infinite scrolling with Ionic2 and Firebase.
我使用AngularFire2。我想做的是将新项添加到提取的列表中,而不是重新加载整个列表。
I use AngularFire2. What I'd like to do is to add new items to the fetched list and not to reload the whole list.
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();
然而,当我查询这样的列表时,每次通过websockets重新加载整个列表更新越来越慢。
以下是网络网页框标签的屏幕截图:
我还注意到每个下一个块的请求都是2次(尽管我放了publishReplay) 。它发生在我使用AngularFire2的所有应用程序中。
我可能会误解一些东西。我当然需要澄清一下。
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: 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.
// ==========编辑============
//==========Edit============
现在,我以某种方式设法实现了我想要的,而不是每次都重新加载整个列表。不是最好的实现,但它的工作原理。基本上,我创建了一个可观察的数组,并通过订阅下一个chunk observable(其中我也得到了最后一个元素)来加载新的值。
但是后面的问题仍然存在 - 在套接字显示中我得到了2次请求的数据。
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.
推荐答案
使用observables 查询
选项就是这样不起作用。底层SDK中没有任何工具可以动态修改查询的 limitToFirst
,并且无法在AngularFire2中执行此操作。
Using observables for query
options just does not work like that. There is no facility in the underlying SDK to dynamically modify a query's limitToFirst
and there's no way of doing it in AngularFire2.
每次可观察的查询
选项发出新值时,都会创建一个新的Firebase引用。您可以在源于此处。
Each time an observable query
option emits a new value, a new Firebase ref is created. You can see it in the source here.
但是,可以通过执行以下操作来创建表示无限列表的observable:
However, it would be possible to create an observable that represents an infinite list by doing something like this:
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将不会能够可靠地翻阅结果,直到此问题重新打开并解决。
That will work, but if the child upon which you are ordering has duplicate values, AngularFire2 won't be able to page through the results reliably until this issue is re-opened and resolved.
结果列表是静态的。也就是说,如果数据库发生更改,则不会更新已列入列表的子项。实现动态列表更具挑战性,因为基于限制的分页机制可以轻松实现重复和丢失的子项。
The resultant list is static. That is, children already paged in to the list won't be updated if the database changes. Implementing a dynamic list is more challenging, as duplicated and missing children can easily be effected by the limit-based paging mechanism.
自从写这个答案以来,我已经在我开源的Firebase可观察库中提供了正向和反向,非实时和实时无限列表可观察量的经过测试的实现。请参阅此GitHub回购。
Since writing this answer, I've made available tested implementations of forward and reverse, non-realtime and realtime infinite list observables in a library of Firebase observables that I have open sourced. See this GitHub repo.
这篇关于AngularFire2无限滚动的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!