typescript - rxjs her sayfaya abonelik ile sayfalama


Bir dizi varlığa abone olmak için websocket üzerinden graphql sorgusu yapıyoruz. Listenin sonsuz kaydırılabilir olması gerektiğinden sayfalandırma kullanıyoruz. Ayrıca ön uçtaki listede veritabanında yapılan değişiklikleri gerçek zamanlı olarak görmek istiyoruz.

Bu liste filtrelenebilir, sıralanabilir ve sayfalanabilir.

Bunu yapmamıza yardımcı olan SelectParams sınıfımız var:

export class SelectParams {
    page = 0;
    query = '';
    sort: Sort = { sortBy: 'creationDate', sortOrder: 'DESC' };
    take = 30;
}

Sonra bir listeye abone olmak istediğimizde, sadece bir selectParams$=Observable<SelectParams> veririz ve bu, selectParams$ içindeki değişikliklere tepki veren "reaktif" listeyi alır. Bu şöyle kullanılır:

    this.items$ = this.featureSrv.selectMany(this.selectParams$)

Kameranın altında selectMany şöyle çalışır:

// when we call selectMany we just push the params to the pipeline
selectMany(params$: Observable<SelectParams> = of(new SelectParams())): Observable<T[]> {
    this.selectManyParams$.next(params$);
    return this.selectMany$;
}

// subject where we push params to sort, paginate and filter
selectManyParams$ = new ReplaySubject<Observable<SelectParams>>(1);
// when the params change then so does this observable, which is returned by the selectMany function
selectMany$ = this.selectManyParams$.asObservable().pipe(
    // retrieve params from their observable form
    flatMap(params$ => params$),
    // when the params haven't changed we shouldn't do anything
    distinctUntilChanged(),
    // then we query graphql to get a suscription to some part of the data
    switchMap(({ page, sort, query, take }: SelectParams) => {
    // the selectMany here is a subscription to some data on the server
        return this.apolloWrapper.selectMany(this.gql, page, sort, query, take ).pipe(
    // we add page data so we can use it in the scan
            map(data => ({ data, page }) as any)
        );
    }),
    // we append the result if page was incremented
    // else we just return the result
    scan((acc: any, curr: any) => curr.page === 0 ? curr.data : acc.concat(curr.data), [])
);

this.apolloWrapper.selectMany metodu, websocket üzerinden verinin belirli bir dilimi üzerinde abonelik yapan kendimizin oluşturduğu bir metottur. Diyelim ki page=0, o zaman this.apolloWrapper.selectMany verinin ilk dilimine abonelik döndürecektir, ardından page=1 olduğunda, this.apolloWrapper.selectMany verinin ikinci dilimine abonelik döndürecektir.

Sorun, ikinci sayfayı yüklediğimizde ve ilk dilimdeki öğelerde bir değişiklik yaptığımızda ortaya çıkar; scan tetiklenir ve öğeler listenin sonuna yeniden eklenir.