How to reset a RXJS scan operator based on another Observable

后端 未结 3 854
无人共我
无人共我 2021-01-18 03:49

I have a component which triggers an onScrollEnd event when the last item in a virtual list is rendered. This event will do a new API request to fetch the next

相关标签:
3条回答
  • 2021-01-18 04:06

    This is an interesting stream. Thinking about it, offset$ and search$ are really 2 separate streams, though, with different logic, and so should be merged at the very end and not the beginning.

    Also, it seems to me that searching should reset the offset to 0, and I don't see that in the current logic.

    So here's my idea:

    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);
    

    See if that works or would make sense. I may be missing some context.

    0 讨论(0)
  • 2021-01-18 04:10

    Found a working solution: I check the current offset by using withLatestFrom before the scan operator and reset the accumulator if needed based on this value.

    Stackblitz demo

    0 讨论(0)
  • 2021-01-18 04:17

    I think you could achieve what you want just by restructuring your chain (I'm omitting tap calls that trigger loading for simplicity):

    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], []),
        ),
      ),
    );
    

    Every emission from search$ will create a new inner Observable with its own scan that will start with an empty accumulator.

    0 讨论(0)
提交回复
热议问题