TypeScript - RxJS الترقيم مع الاشتراك في كل صفحة


نحن نقوم بالاستعلام من graphql عبر websocket للحصول على اشتراك في قائمة من الكيانات. نستخدم التجزئة لأن القائمة من المفترض أن تكون قابلة للتمرير إلى ما لا نهاية. نريد أيضًا رؤية التغييرات التي تطرأ على قاعدة البيانات في الوقت الفعلي في القائمة على الواجهة الأمامية.

يمكن تصفية هذه القائمة وفرزها وتقسيمها إلى صفحات.

لدينا الصف SelectParams الذي يساعدنا على القيام بذلك:

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

ثم عندما نريد الاشتراك في قائمة، نقوم فقط بإعطاء selectParams$= Observable<SelectParams> للحصول على القائمة التي هي "تفاعلية" وتتفاعل مع التغييرات في selectParams$. يتم استخدام هذا على النحو التالي:

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

تحت الغطاء يعمل selectMany هكذا:

// 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 هي طريقة أنشأناها تقوم ببساطة بالاشتراك عبر الويب سوكيت على جزء من البيانات. لنفترض أن page=0، عندها ستعيد this.apolloWrapper.selectMany اشتراكًا في الجزء الأول من البيانات، ثم عندما يكون page=1، تعيد this.apolloWrapper.selectMany اشتراكًا في الجزء الثاني من البيانات.

تنشأ المشكلة عندما نقوم بتحميل الصفحة الثانية وإجراء تعديل على العناصر في القسم الأول، ثم يتم تشغيل scan ويعاد إضافة العناصر إلى نهاية القائمة.