TypeScript - RxJS การแบ่งหน้าพร้อมการสมัครสมาชิกกับแต่ละหน้า
เรากำลังสอบถาม graphql ผ่าน websocket เพื่อมีการสมัครรับรายการของเอนทิตี เราใช้การแบ่งหน้าเนื่องจากรายการนี้ควรเลื่อนดูได้ไม่จำกัด เรายังต้องการเห็นการเปลี่ยนแปลงที่เกิดขึ้นในฐานข้อมูลแบบเรียลไทม์ในรายการที่ด้านหน้าด้วย
รายชื่อนี้สามารถ กรอง, เรียงลำดับ และ แบ่งหน้า ได้
เรามีคลาส SelectParams ที่ช่วยให้เราทำสิ่งนั้นได้:
export class SelectParams {
page = 0;
query = '';
sort: Sort = { sortBy: 'creationDate', sortOrder: 'DESC' };
take = 30;
}
แล้วเมื่อเราต้องการสมัครรับรายการ เราก็เพียงแค่ให้ selectParams$=Observable<SelectParams> เพื่อรับรายการที่เป็น "reactive" และตอบสนองต่อการเปลี่ยนแปลงใน 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 เป็นวิธีที่เราสร้างขึ้นที่ทำการสมัครสมาชิกผ่าน websocket ไปยังบางส่วนของข้อมูล สมมติว่าเรามี page=0 แล้ว this.apolloWrapper.selectMany จะส่งกลับการสมัครสมาชิกไปยังส่วนแรกของข้อมูล แล้วเมื่อ page=1 this.apolloWrapper.selectMany จะส่งกลับการสมัครสมาชิกไปยังส่วนที่สองของข้อมูล
ปัญหาเกิดขึ้นเมื่อเราโหลดหน้าที่สองและทำการแก้ไขรายการในสไลซ์แรก จากนั้น scan จะถูกเรียกใช้งานและรายการจะถูกเพิ่มกลับไปที่ท้ายรายการอีกครั้ง