2017-02-07 6 views
2

Ionic2와 Firebase로 무한 스크롤을 구현하려고합니다.AngularFire2 무한 스크롤

저는 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(); 

그러나 전체 목록은 느린 속도가 느린 각각 다음 업데이트를 만드는 WebSocket을 통해 때마다 다시로드됩니다. 다음은 Network websockets 탭의 스크린 샷입니다. websockets 또한 다음 청크마다 요청이 2 번 (publishReplay를 넣었음에도 불구하고) 나타났습니다. 그리고 AngularFire2를 사용하는 모든 앱에서 이러한 현상이 발생합니다. 나는 오해 할 수도 있습니다. 명확한 설명이 필요합니다.

// ==========

지금, 어떻게 든 관리 편집 ============ 때마다 전체 목록을 다시로드하지 않고 내가 원하는 것을 구현 . 최고의 구현은 아니지만 작동합니다. 기본적으로 관찰 가능한 배열을 생성하고 다음 덩어리 관측 가능 항목에 가입하여 새 값을로드합니다. 여기서 마지막 요소는 어디서부터 시작해야 할지를 나타냅니다. 그러나 나중의 문제는 여전히 남아 있습니다 - 소켓 디스플레이에서 2 번 요청 된 데이터를 얻습니다. enter image description here

+0

전체 목록의 의미는 무엇입니까? 5 항목을 요청했습니다. 그런 다음 10 점을 요구했습니다. 처음 5 점은 요청한 10 점의 일부입니다. 그것은 당신의 기대가 아닌가요? – Rexford

+0

나는 전체 목록이 firebase에서 요청되어 이미로드 된 항목을 다시로드하는 것을 의미했습니다.예상되는 동작이지만 각 상한에 대해 원하는 동작이 아 닌 경우 로딩 시간이 길어집니다. –

답변

5

관찰 대상을 query에 사용하면 옵션이 제대로 작동하지 않습니다. 기본 SDK에는 쿼리의 limitToFirst을 동적으로 수정하는 기능이 없으며 AngularFire2에서 수행 할 방법이 없습니다.

관찰 가능한 query 옵션이 새로운 값을 방출 할 때마다 새로운 Firebase ref가 생성됩니다. source here에서 확인할 수 있습니다.

그러나,이 같은 수행하여 무한한 목록을 나타냅니다 관측 만들 수있을 것입니다 :

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을 중복 값을 가지고있는시 아이 this issue이 다시 열리고 해결 될 때까지 결과를 신뢰할 수있게 페이징 할 수 없습니다.

결과 목록은 정적입니다. 즉, 목록에 이미 페이징 된 하위 항목은 데이터베이스가 변경된 경우 업데이트되지 않습니다. 동적 목록을 구현하는 것은 더 어렵습니다. 중복 및 누락 된 하위 항목은 제한 기반 호출 메커니즘으로 쉽게 영향을받을 수 있기 때문입니다.


이 답을 쓰기 때문에, 나는 오픈 소스 화를 중포 기지의 관찰 가능한 라이브러리에 순방향 및 역방향의 가능한 테스트 구현, 비 실시간 및 실시간 무한리스트 관찰 가능한을했습니다. this GitHub repo을 참조하십시오.

+0

답해 주셔서 감사합니다. 나는 조금 다른 방식으로 그것을 해결했다. 당신의 해결책은 더 예쁘다. 그리고 그것은 훌륭한 RxJS 수업입니다. 질문의 두 번째 부분을 살펴볼 수도 있습니까? 이런 식으로되어 있는지 나는 모른다. –

+0

두 번째 부분으로 두 번 전송되는 정보를 의미합니까? 나는 내일 그것을 빨리 볼 것이다. – cartant

+0

두 번 검색되는 데이터를 보여주는 WebSocket 트래픽과 관련하여 내가 버그라고 생각하는 것을 발견했습니다. AngularFire2 팀과 이야기하고 있습니다. – cartant

2

cartant's answer에 끝에 추가하고 목록 항목을 역순으로 검색하려면 다음과 같이하십시오 (코드가 변경된 곳의 주석을 추가했습니다).

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 

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

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

     // Use limitToLast to move upward the list instead of downward 

     limitToLast: last ? (pageSize + 1) : pageSize, 
     orderByChild: "date_published", 

     // Use endAt to start at the end of the list 

     endAt: last 
     } 
    }) 
    .first() 
) 

    .scan((acc, list) => { 

    // Swap the roles of acc and list, as we want to 
    // concatenate from the beginning 

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

    .share(); 



last = infiniteList 
    .filter((list) => list.length > 0) 

    // Use the first child in this list as the next endAt value 

    .map((list) => list[0].date_published) 

    // Use undefined instead of null, as endAt: null in angularfire2 
    // will search for the last child that is null 

    .startWith(undefined); 

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

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