簡體   English   中英

如何根據另一個 Observable 重置 RXJS 掃描運算符

[英]How to reset a RXJS scan operator based on another Observable

我有一個組件,它在呈現虛擬列表中的最后一個項目時觸發onScrollEnd事件。 此事件將執行新的 API 請求以獲取下一頁並使用scan運算符將它們與先前的結果合並。

該組件還有一個搜索字段,用於觸發onSearch事件。

觸發搜索事件時,如何清除scan操作員之前累積的結果? 或者我需要在這里重構我的邏輯嗎?

const loading$ = new BehaviorSubject(false);
const offset$ = new BehaviorSubject(0);
const search$ = new BehaviorSubject(null);

const options$: Observable<any[]> = merge(offset$, search$).pipe(
  // 1. Start the loading indicator.
  tap(() => loading$.next(true)),
  // 2. Fetch new items based on the offset.
  switchMap(([offset, searchterm]) => userService.getUsers(offset, searchterm)),
  // 3. Stop the loading indicator.
  tap(() => loading$.next(false)),
  // 4. Complete the Observable when there is no 'next' link.
  takeWhile((response) => response.links.next),
  // 5. Map the response.
  map(({ data }) =>
    data.map((user) => ({
      label: user.name,
      value: user.id
    }))
  ),
  // 6. Accumulate the new options with the previous options.
  scan((acc, curr) => {
    // TODO: Dont merge on search$.next 
    return [...acc, ...curr]);
  }
);

// Fetch next page
onScrollEnd: (offset: number) => offset$.next(offset);
// Fetch search results
onSearch: (term) => {
  search$.next(term);
};

我認為你可以通過重組你的鏈來實現你想要的(為了簡單起見,我省略了觸發加載的tap調用):

search$.pipe(
  switchMap(searchterm =>
    concat(
      userService.getUsers(0, searchterm),
      offset$.pipe(concatMap(offset => userService.getUsers(offset, searchterm)))),
    ).pipe(
      map(({ data }) => data.map((user) => ({
        label: user.name,
        value: user.id
      }))),
      scan((acc, curr) => [...acc, ...curr], []),
    ),
  ),
);

search$每次發射都將創建一個新的內部 Observable,它具有自己的scan ,該scan將從一個空的累加器開始。

找到了一個withLatestFrom解決方案:我在scan運算符之前使用withLatestFrom檢查當前偏移量,並根據此值在需要時重置累加器。

Stackblitz 演示

這是一個有趣的流。 仔細想想,offset$ 和 search$ 實際上是 2 個獨立的流,但具有不同的邏輯,因此應該在最后而不是開始時合並。

另外,在我看來,搜索應該將偏移量重置為 0,而我在當前邏輯中沒有看到這一點。

所以這是我的想法:

const offsettedOptions$ = offset$.pipe(
    tap(() => loading$.next(true)),    
    withLatestFrom(search$),
    concatMap(([offset, searchterm]) => userService.getUsers(offset, searchterm)),
    tap(() => loading$.next(false)),
    map(({ data }) =>
    data.map((user) => ({
      label: user.name,
      value: user.id
    })),
    scan((acc, curr) => [...acc, ...curr])
);

const searchedOptions$ = search$.pipe(
    tap(() => loading$.next(true)),
    concatMap(searchTerm => userService.getUsers(0, searchterm)),
    tap(() => loading$.next(false)),
    map(({ data }) =>
    data.map((user) => ({
      label: user.name,
      value: user.id
    })),
);

const options$ = merge(offsettedOptions, searchedOptions);

看看這是否有效或有意義。 我可能缺少一些上下文。

要操縱scanstate ,您可以編寫高階函數來獲取舊狀態和新更新。 然后與合並運算符組合

 const { Subject, merge } = rxjs; const { scan, map } = rxjs.operators; add$ = new Subject(); clear$ = new Subject(); add = (value) => (state) => [...state, value]; clear = () => (state) => []; const result$ = merge( add$.pipe(map(add)), clear$.pipe(map(clear)) ).pipe( scan((state, innerFn) => innerFn(state), []) ) result$.subscribe(console.log) add$.next(1) add$.next(2) clear$.next() add$.next(3)
 <script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.5.3/rxjs.umd.min.js"></script>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM